Dynamo Primer Clear Version
Dynamo Primer Clear Version
About
1.
Introduction
1.1.
What is Visual Programming?
1.2.
What is Dynamo?
1.3.
Dynamo in Action
2.
Hello Dynamo!
2.1.
Installing and Launching Dynamo
2.2.
The User Interface
2.3.
The Workspace
2.4.
Getting Started
3.
The Anatomy of a Visual Program
3.1.
Nodes
3.2.
Wires
3.3.
Library
3.4.
Managing Your Program
4.
The Building Blocks of Programs
4.1.
Data
4.2.
Math
4.3.
Logic
4.4.
Strings
4.5.
Color
5.
Geometry for Computational Design
5.1.
Geometry Overview
5.2.
Vectors
5.3.
Points
5.4.
Curves
5.5.
Surfaces
5.6.
Solids
5.7.
Meshes
5.8.
Importing Geometry
6.
Designing with Lists
6.1.
What's a List
6.2.
Working with Lists
6.3.
Lists of Lists
6.4.
n-Dimensional Lists
7.
Code Blocks and DesignScript
7.1.
What's a Code Block
7.2.
DesignScript Syntax
7.3.
Shorthand
7.4.
Functions
8.
Dynamo for Revit
8.1.
The Revit Connection
8.2.
Selecting
8.3.
Editing
8.4.
Creating
8.5.
Customizing
8.6.
Documenting
9.
Dictionaries in Dynamo
9.1.
What is a Dictionary
9.2.
Node Uses
9.3.
Code Block Uses
9.4.
Use-Cases
10. Custom Nodes
10.1.
Custom Node Introduction
10.2.
Creating a Custom Node
10.3.
Publishing to Your Library
10.4.
Python Nodes
10.5.
Python and Revit
10.6.
Python Templates in Dynamo 2.0
11. Packages
11.1.
Package Introduction
11.2.
Package Case Study - Mesh Toolkit
11.3.
Developing a Package
11.4.
Publishing a Package
11.5.
Zero-Touch Importing
12. Geometry with DesignScript
12.1.
DesignScript Geometry Basics
12.2.
Geometric Primitives
12.3.
Vector Math
12.4.
Curves: Interpolated and Control Points
12.5.
Translation, Rotation, and Other Transformations
12.6.
Surfaces: Interpolated, Control Points, Loft, Revolve
12.7.
Geometric Parameterization
12.8.
Intersection and Trim
12.9.
Geometric Booleans
12.10.
Python Point Generators
13. Best Practices
13.1.
Graph Strategies
13.2.
Scripting Strategies
13.3.
Scripting Reference
14. Appendix
14.1.
Resources
14.2.
Index of Nodes
14.3.
Useful Packages
14.4.
Example Files
Facebook
Facebook Google+
Google+ Twitter
Twitter Weibo
Weibo Instapaper
Instapaper
Languages
Deutsch
Deutsch 日本語 中文(繁體) 中文( 体) Français
日本語 中文 Français
中文 Čeština
Č Italiano
Italiano 한국어
한국어
Polski
Polski Português(Brasil)
Português(Brasil) Русский
Русский Español
Español
A
A A
A
Serif
Serif Sans
Sans
White
White Sepia
Sepia Night
Night
Welcome
You have just opened the Dynamo Primer, a comprehensive guide to visual programming in
Autodesk Dynamo Studio. This primer is an on-going project to share the fundamentals of
programming. Topics include working with computational geometry, best practices for rules-
based design, cross-disciplinary programming applications, and more with the Dynamo
Platform.
The power of Dynamo can be found in a wide variety of design-related activities. Dynamo
enables an expanding list of readily accessible ways for you to get started:
Explore visual programming for the frst time
Connect workfows in various software
Engage an active community of users, contributors, and developers
Develop an open-source platform for continued improvement
In the midst of this activity and exciting opportunity for working with Dynamo, we need a
document of the same caliber, the Dynamo Primer.
This Primer includes chapters developed with Mode Lab. These chapters focus on the
essentials you will need to get up and running developing your own visual programs with
Dynamo and key insights on how to take Dynamo further. Here's what you can expect to learn
from the primer:
Context - What exactly is "Visual Programming" and what are the concepts I need to
understand to dive in to Dynamo?
Getting Started - How do I get Dynamo and create my frst program?
What's in a Program - What are the functional parts of Dynamo and how do I use them?
Building Blocks - What is "Data" and what are some fundamental types I can start using in
my programs?
Geometry for Design - How do I work with geometric elements in Dynamo?
Lists, Lists, Lists - How to do I manage and coordinate my data structures?
Code in Nodes - How can I start extending Dynamo with my own code?
Computational BIM - How can I use Dynamo with a Revit model?
Custom Nodes - How can I create my own nodes?
Packages - How can I share my tools with the community?
This is an exciting time to be learning about, working with, and developing for Dynamo. Let's
get started!
Open Source
The Dynamo Primer project is open source! We're dedicated to providing quality content and
appreciate any feedback you may have. If you would like to report an issue on anything at all,
please post them on our GitHub issue page:
https://github.com/DynamoDS/DynamoPrimer/issues
If you would like to contribute a new section, edits, or anything else to this project, check out
the GitHub repo to get started: https://github.com/DynamoDS/DynamoPrimer.
Mode Lab was commissioned to write the First Edition of the primer. We thank them for all of
their efforts in establishing this valuable resource.
John Pierson of Parallax Team was commissioned to update the primer to refect the Dynamo
2.0. revisions.
Acknowledgments
A special thanks to Ian Keough for initiating and guiding the Dynamo project.
Thank you to Matt Jezyk, Ian Keough, Zach Kron, Racel Williams and Colin McCrone for
enthusiastic collaboration and the opportunity to participate on a wide array of Dynamo
projects.
Software and Resources
Dynamo The current stable* release of Dynamo is Version 2.1.0
http://dynamobim.com/download/ or http://dynamobuilds.com
*Note: Starting with Revit 2020, Dynamo is bundled with Revit releases, resulting in manual
installation not being required. More information is available at this blog post.
DynamoBIM The best source for additional information, learning content, and forums is the
DynamoBIM website.
http://dynamobim.org
https://github.com/DynamoDS/Dynamo
License
Copyright 2019 Autodesk
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this fle
except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
ANY KIND, either express or implied. See the License for the specifc language governing
permissions and limitations under the License.
INTRODUCTION
From its origins as an add-on for Building Information Modeling in Revit, Dynamo has matured
to become many things. Above all else it is a platform, enabling designers to explore visual
programming, solve problems, and make their own tools. Let's start our journey with Dynamo
by setting some context - what is it and how do I approach using it?
〒1 三
What is Visual Programming?
Designing frequently involves establishing visual, systemic, or geometric relationships between
the parts of a design. More times than not, these relationships are developed by workfows that
gets us from concept to result by way of rules. Perhaps without knowing it, we are working
algorithmically - defning a step-by-step set of actions that follow a basic logic of input,
processing, and output. Programming allows us to continue to work this way but by formalizing
our algorithms.
Algorithms in Hand
While offering some powerful opportunities, the term Algorithm can carry some misconceptions
with it. Algorithms can generate unexpected, wild, or cool things, but they are not magic. In
fact, they are pretty plain, in and of themselves. Let's use a tangible example like an origami
crane. We start with a square piece of paper (input), follow a series of folding steps
(processing actions), and result in a crane (output).
So where is the Algorithm? It is the abstract set of steps, which we can represent in a couple of
ways - either textually or graphically.
Textual Instructions:
1. Start with a square piece of
paper, colored side up. Fold in half and open. Then fold in half
the other way.
2. Turn the paper over to the white side. Fold the paper in half, crease well and open, and
then fold again in the other direction.
3. Using the creases you have made, Bring the top 3 corners of the model down to the
bottom corner. Flatten model.
4. Fold top triangular faps into the center and unfold.
5. Fold top of model downwards, crease well and unfold.
6. Open the uppermost fap of the model, bringing it upwards and pressing the sides of the
model inwards at the same time. Flatten down, creasing well.
7. Turn model over and repeat Steps 4-6 on the other side.
8. Fold top faps into the center.
9. Repeat on other side.
10. Fold both ‘legs’ of model up, crease very well, then unfold.
11. Inside Reverse Fold the “legs” along the creases you just made.
12. Inside Reverse Fold one side to make a head, then fold down the wings.
13. You now have a crane.
Graphical Instructions:
Programming Defned
Using either of these sets of instructions should result in a crane, and if you followed along
yourself, you've applied an algorithm. The only difference is the way in which we read the
formalization of that set of instructions and that leads us to Programming. Programming,
frequently shortened from Computer Programming, is the act of formalizing the processing of a
series of actions into an executable program. If we turned the above instructions for a creating
crane into a format our computer can read and execute, we are Programming.
The key to and frst hurdle we will fnd in Programming, is that we have to rely on some form of
abstraction to communicate effectively with our computer. That takes the form of any number
of Programming Languages, such as JavaScript, Python, or C. If we can write out a repeatable
set of instructions, like for the origami crane, we only need to translate it for the computer. We
are on our way to having the computer be able to make a crane or even a multitude of different
cranes where each one varies slightly. This is the power of Programming - the computer will
repeatedly execute whatever task, or set of tasks, we assign to it, without delay and without
human error.
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Visual Programming - Circle Through Point.dyn. A full list of example fles can be
found in the Appendix.
If you were tasked with writing instructions for folding an origami crane, how would you go
about it? Would you make them with graphics, text, or some combination of the two?
If your answer contained graphics, then Visual Programming is defnitely for you. The process
is essentially the same for both Programming and Visual Programming. They utilize the same
framework of formalization; however, we defne the instructions and relationships of our
program through a graphical (or "Visual") user interface. Instead of typing text bound by
syntax, we connect pre-packaged nodes together. Here's a comparison of the same algorithm -
"draw a circle through a point" - programmed with nodes versus code:
Visual Program:
Textual Program:
myPoint = Point.ByCoordinates(0.0,0.0,0.0);
x = 5.6;
y = 11.5;
attractorPoint = Point.ByCoordinates(x,y,0.0);
dist = myPoint.DistanceTo(attractorPoint);
myCircle = Circle.ByCenterPointRadius(myPoint,dist);
The visual characteristic to programming in such a way lowers the barrier to entry and
frequently speaks to designers. Dynamo falls in the Visual Programming paradigm, but as we
will see later, we can still use textual programming in the application as well.
What is Dynamo?
Dynamo is, quite literally, what you make it. Working with Dynamo may include using the
application, either in connection with other Autodesk software or not, engaging a Visual
Programming process, or participating in a broad community of users and contributors.
The Application
Dynamo, the application, is a software that can be downloaded and run in either stand-alone
"Sandbox" mode or as a plug-in for other software like Revit or Maya. It is described as:
The Process
Once we've installed the application, Dynamo will enable us to work within a Visual
Programming process wherein we connect elements together to defne the relationships and
the sequences of actions that compose custom algorithms. We can use our algorithms for a
wide array of applications - from processing data to generating geometry - all in real time and
without writing a lick of code .
Add elements, connect, and we are off and running with creating Visual Programs.
The Community
Dynamo wouldn't be what it is without a strong group of avid users and active contributors.
Engage the community by following the Blog, adding your work to the Gallery, or discussing
Dynamo in the Forum.
The Platform
Dynamo is envisioned as a visual programming tool for designers, allowing us to make tools
that make use of external libraries or any Autodesk product that has an API. With Dynamo
Studio we can develop programs in a "Sandbox" style application - but the Dynamo ecosystem
continues to grow.
The source code for the project is open-source, enabling us to extend its functionality to our
hearts content. Check out the project on GitHub and browse the Works in Progress of users
customizing Dynamo.
Browse, Fork, and start extending Dynamo for your needs
HELLO DYNAMO!
At its core, Dynamo is a platform for Visual Programming - it is a fexible and extensible design
tool. Because it can operate as a stand-alone application or as an add-on to other design
software, we can use it to develop a wide range of creative workfows. Let's install Dynamo and
get started by reviewing the key features of the interface.
Installing and Launching Dynamo
Dynamo is an active open-source development project with downloadable installers for both
offcial and pre-release, i.e.. "daily build" versions. Download the offcial release to get started,
or contribute to what Dynamo becomes through the daily builds or GitHub project.
Downloading
To download the offcial released version of Dynamo, visit the Dynamo website. Start the
download immediately by clicking from the homepage or browse to the dedicated download
page.
Here you can download the "bleeding edge" development versions or go to the Dynamo Github
project.
1. Download the offcial release installer
2. Download the daily build installers
3. Check out custom packages from a community of developers
4. Get involved in the development of Dynamo on GitHub
Installing
Browse to the directory of the downloaded installer and run the executable fle. During the
installation process, the setup allows you to customize the components that will be installed.
1. Select the Components you want to install
Here we need to decide if we want to include the components that connect Dynamo to other
installed applications such as Revit. For more information on the Dynamo Platform, see
Chapter 1.2.
Launching
To launch Dynamo, browse to \Program Files\Dynamo\Dynamo Revit\x.y, then select
DynamoSandbox.exe. This will open the stand-alone version and present Dynamo's Start
Page. On this page, we see the standard menus and toolbar as well as a collection of
shortcuts that allow us to access fle functionality or access additional resources.
1. Files - Start a new fle or open an existing one
2. Recent - Scroll through your recent fles
3. Backup - Access to your backups
4. Ask - Get direct access to the User Forum or Dynamo Website
5. Reference - Go further with additional learning resources
6. Code - Participate in the open-source development project
7. Samples - Check out the examples that come with the installation
Open the frst sample fle to open your frst workspace and confrm Dynamo is working
correctly. Click Samples > Basics > Basics_Basic01.dyn.
1. Confrm that the Execution Bar says "Automatic" or click Run
2. Follow the instructions and connect the Number Node to the + Node
3. Confrm that this Watch Node shows a result
If this fle successfully loads, you should be able to execute your frst visual program with
Dynamo.
The Dynamo User Interface
The User Interface (UI) for Dynamo is organized into fve main regions, the largest of which is
the workspace where we compose our visual programs.
1. Menus
2. Toolbar
3. Library
4. Workspace
5. Execution Bar
Let's dive deeper into the UI and explore the functionality of each region.
Menus
The Dropdown Menus are a great place to fnd some of the basic functionality of the Dynamo
application. Like most Windows software, actions related to managing fles and operations for
selection and content editing are found in the frst two menus. The remaining menus are more
specifc to Dynamo.
1. File
2. Edit
3. View
4. Packages
5. Settings
6. Help
7. Notifcations
Toolbar
Dynamo's Toolbar contains a series of buttons for quick access to working with fles as well as
Undo [Ctrl + Z] and Redo [Ctrl + Y] commands. On the far right is another button that will
export a snapshot of the workspace, which is extremely useful for documentation and sharing.
1. New - Create a new .dyn fle
2. Open - Open an existing .dyn (workspace) or .dyf (custom node) fle
3. Save/Save As - Save your active .dyn or .dyf fle
4. Undo - Undo your last action
5. Redo - Redo the next action
6. Export Workspace as Image - Export the visible workspace as a PNG fle
Library
The Library contains all of the loaded Nodes, including the default Nodes that come with the
installation as well as any additionally loaded Custom Nodes or Packages. The Nodes in the
Library are organized hierarchically within libraries, categories, and, where appropriate, sub-
categories based on whether the Nodes Create data, execute an Action, or Query data.
Browsing
By default, the Library will contain eight categories of Nodes. Core and Geometry are great
menus to begin exploring as they contain the largest quantity of Nodes. Browsing through
these categories is the fastest way to understand the hierarchy of what we can add to our
Workspace and the best way to discover new Nodes you haven't used before.
We will focus on the default collection of Nodes now, but note that we will extend this
Library with Custom Nodes, additional libraries, and the Package Manager later.
1. Dictionary
2. Display
3. Geometry
4. ImportExport
5. Input
6. List
7. Matches
8. Revit
9. Script
10. String
11. Add-ons
Browse the Library by clicking through the menus. Click the Geometry > Curves > Circle. Note
the new portion of the menu that is revealed and specifcally the Create and Query Labels.
1. Library
2. Category
3. Subcategory: Create/Actions/Query
4. Node
5. Node Description and properties - this appears when hovering over the node icon.
From the same Circle menu, hover your mouse over ByCenterPointRadius. The window
reveals more detailed information about the Node beyond its name and icon. This offers us a
quick way to understand what the Node does, what it will require for inputs, and what it will give
as an output.
1. Description - plain language description of the Node
2. Icon - larger version of the icon in the Library Menu
3. Input(s) - name, data type, and data structure
4. Output(s) - data type and structure
Searching
If you know with relative specifcity which Node you want to add to your Workspace, the
Search feld is your best friend. When you are not editing settings or specifying values in the
Workspace, the cursor is always present in this feld. If you start typing, the Dynamo Library
will reveal a selected best ft match (with breadcrumbs for where it can be found in the Node
categories) and a list of alternate matches to the search. When you hit Enter, or click on the
item in the truncated browser, the highlighted Node is added to the center of the Workspace.
1. Search Field
2. Best Fit Result / Selected
3. Alternate Matches
Settings
From geometric to user settings, these options can be found in the Settings menu. Here you
can opt in or out for sharing your user data to improve Dynamo as well as defne the
application's decimal point precision and geometry render quality.
1. Enabling Reporting - Options for sharing user data to improve Dynamo.
2. Show Run Preview - Preview the execution state of your graph. Nodes scheduled for
execution will be highlighted in your graph.
3. Number Format Options - Change the document settings for decimals.
4. Render Precision - Raise or lower the document render quality.
5. Geometry Scaling - Select range of geometry you are working on.
6. Isolate Selected Geometry - Isolated background geometry based on your node
selection.
7. Show/Hide Geometry Edges - Toggle 3D geometry edges.
8. Show/Hide Preview Bubbles - Toggle data preview bubbles below nodes.
9. Manage Node and Package Paths - Manage fle paths to make nodes and packages
show up in the Library.
10. Enabling Experimental Features - Use beta features new in Dynamo.
Help
If you're stuck, check out the Help Menu. Here you can fnd the sample fles that come with
your installation as well as access one of the Dynamo reference websites through your internet
browser. If you need to, check the version of Dynamo installed and whether it is up to date
through the About option.
The Workspace
The Dynamo Workspace is where we develop our visual programs, but it's also where we
preview any resulting geometry. Whether we are working in a Home Workspace or a Custom
Node, we can navigate with our mouse or the buttons at top right. Toggling between modes at
bottom right switches which preview we navigate.
Note: Nodes and geometry have a draw order so you may have objects rendered on top
of each other. This can be confusing when adding multiple nodes in sequence as they
may be rendered in the same position in the Workspace.
1. Tabs
2. Zoom/Pan Buttons
3. Preview Mode
4. Double Clicking on the Workspace
Tabs
The active Workspace tab allows you to navigate and edit your program. When you open a
new fle, by default you are opening a new Home Workspace. You may also open a new
Custom Node Workspace from the File Menu or by the New Node by Selection right click
option when Nodes are selected (more on this functionality later).
Note: You may have only one Home Workspace open at a time; however, you may have
multiple Custom Node Workspaces open in additional tabs.
The 3D Preview Navigation mode also gives us the ability for Direct Manipulation of points,
exemplifed in Getting Started.
Zoom to Recenter
We can easily pan, zoom and rotate freely around models in 3D Preview Navigation mode.
However, to zoom specifcally on an object created by a geometry node, we can use the Zoom
All icon with a single node selected.
1. Select the node corresponding to the geometry that will center the view.
2. Switch to the 3D Preview Navigation.
1. Right click anywhere on the canvas to bring up the search feature. While the search
bar is empty, the drop-down will be a preview menu.
2. As you type into the search bar, the drop-down menu will continuously update to
show the most relevant search results.
3. Hover over the search results to bring up their corresponding descriptions and tool-
tips.
Keeping your Dynamo canvas organized becomes increasingly important as your fles build in
complexity. Although we have the Align Selection tool to work with small amounts of selected
Nodes, Dynamo also features the Cleanup Node Layout tool to help with overall fle cleanup.
Before Node Cleanup
1. Select the Nodes to be automatically organized, or leave all unselected to clean up all
nodes in the fle.
2. The Cleanup Node Layout feature is located under the Edit tab.
GETTING STARTED
Now that we have familiarized ourselves with the interface layout and navigating the
Workspace, our next step is to understand the typical workfow for developing a graph in
Dynamo. Let's get started by creating a dynamically sized circle and then create an array of
circles with varying radii.
Adding Detail
If our program is working, we should see a circle in the 3D Preview that is passing through our
Attractor Point. This is great, but we may want to add more detail or more controls. Let's adjust
the input to the circle Node so that we can calibrate the infuence on the radius. Add another
Number Slider to the Workspace, then double click on a blank area of the Workspace to add a
Code Block Node. Edit the feld in the Code Block, specifying X/Y .
1. Code Block
2. DistanceTo and Number Slider to Code Block
3. Code Block to Circle.ByCenterPointRadius
Adding complexity
Starting simple and building complexity is an effective way to incrementally develop our
program. Once it is working for one circle, let's apply the power of the program to more than
one circle. Instead of one center point, if we use a grid of points and accommodate the change
in the resulting data structure, our program will now create many circles - each with a unique
radius value defned by the calibrated distance to the Attractor Point.
1. Add a Number Sequence Node and replace the inputs of Point.ByCoordinates - Right
Click Point.ByCoordinates and select Lacing > Cross Reference
2. Add a Flatten Node after Point.ByCoordinates. To fatten a list completely, leave the
amt input at the default of -1
3. The 3D Preview will update with a grid of circles
1. Hover over the point and the X, Y, and Z axes will appear.
2. Click and drag the colored arrow to move the corresponding axis, and the Number
Slider values will update live with the manually moved point.
1. Note that before Direct Manipulation only one slider was plugged into the
Point.ByCoordinates component. When we manually move the point in the X-
direction, Dynamo will automatically generate a new Number Slider for the X input.
ANATOMY OF A VISUAL PROGRAM
Dynamo enables us to create Visual Programs in a Workspace by connecting Nodes with
Wires to specify the logical fow of the resulting Visual Program. This chapter introduces the
elements of Visual Programs, the organization of the Nodes available in Dynamo's Libraries,
the parts and states of Nodes, and best practices for your Workspaces.
Nodes
In Dynamo, Nodes are the objects you connect to form a Visual Program. Each Node performs
an operation - sometimes that may be as simple as storing a number or it may be a more
complex action such as creating or querying geometry.
Anatomy of a Node
Most Nodes in Dynamo are composed of fve parts. While there are exceptions, such as Input
Nodes, the anatomy of each Node can be described as follows:
Ports
The Inputs and Outputs for Nodes are called Ports and act as the receptors for Wires. Data
comes into the Node through Ports on the left and fows out of the Node after it has executed
its operation on the right. Ports expect to receive data of a certain type. For instance,
connecting a number such as 2.75 to the Ports on a Point By Coordinates Node will
successfully result in creating a Point; however, if we supply "Red" to the same Port it will
result in an error.
Tip: Hover over a Port to see a tooltip containing the data type expected.
1. Port Label
2. Tool Tip
3. Data Type
4. Default Value
States
Dynamo gives an indication of the state of the execution of your Visual Program by rendering
Nodes with different color schemes based on each Node's status. Furthermore, hovering or
right-clicking over the Name or Ports presents additional information and options.
1. Active - Nodes with a Dark Grey Name background are well-connected and have all
of their inputs successfully connected
2. Inactive - Grey Nodes are inactive and need to be connected with Wires to be part of
the Program Flow in the active Workspace
3. Error State - Red indicates that the Node is in an Error State
4. Freeze - A Transparent node has Freeze turned on, suspending the execution of the
node
5. Selected - Currently selected Nodes have an Aqua highlight on their border
6. Warning - Yellow Nodes are in an Warning state, meaning they may have incorrect
data types
7. Background Preview - Dark Grey indicates that the geometry preview is turned off
If your Visual Program contains warning or errors, Dynamo will provide additional information
about the problem. Any Node that is Yellow will also have a tooltip above the Name. Hover
your mouse over the tooltip to expand it.
Tip: With this tooltip information in hand, examine the upstream Nodes to see if the data
type or data structure required is in error.
Wires
Wires connect between Nodes to create relationships and establish the Flow of our Visual
Program. We can think of them literally as electrical wires that carry pulses of data from one
object to the next.
Program Flow
Wires connect the output Port from one Node to the input Port of another Node. This
directionality establishes the Flow of Data in the Visual Program. Although we can arrange our
Nodes however we desire in the Workspace, because the output Ports are located on the right
side of Nodes and the input Ports are on the left side, we can generally say that the Program
Flow moves from left to right.
Creating Wires
We create a Wire by left clicking our mouse on a Port and then left clicking on the port of
another Node to create a connection. While we are in the process of making a connection, the
Wire will appear dashed and will snap to become solid lines when successfully connected. The
data will always fow through this Wire from output to input; however, we may create the wire in
either direction in terms of the sequence of clicking on the connected Ports.
Tip: Before completing the connection with your second click, allow the Wire snap to a
Port and hover your mouse there to see the Port tooltip.
Editing Wires
Frequently we will want to adjust the Program Flow in our Visual Program by editing the
connections represented by the Wires. To edit a Wire, left click on the input Port of the Node
that is already connected. You now have two options:
1. Existing Wire
2. To change the connection to an input Port, left click on another input Port
3. To remove the Wire, pull the Wire away and left click on the Workspace
*Note- There is additionaly functionality for moving multiple wires at once now. This is covered
here http://dynamobim.org/dynamo-1-3-release/
Wire Previews
By default, our Wires will be previewed with a gray stroke. When a Node is selected, it will
render any connecting Wire with the same aqua highlight as the Node.
1. Default Wire
2. Highlighted Wire
Dynamo also allows us to customize how our Wires look in the Workspace through the View >
Connectors Menu. Here we can toggle between Curve or Polyline Wires or turn them off all
together.
1. Connector Type: Curves
2. Connector Type: Polylines
Dynamo Library
The Dynamo Library contains the Nodes we add to the Workspace to defne Visual Programs
for execution. In the Library, we can search for or browse to Nodes. The Nodes contained here
- the basic Nodes installed, Custom Nodes we defne, and Nodes from the Package Manager
that we add to Dynamo - are organized hierachically by category. Let's review this organization
and explore the key Nodes we will use frequently.
Library of Libraries
The Dynamo Library that we interface with in the application is actually a collection of
functional libraries, each containing Nodes grouped by Category. While this may seem obtuse
at frst, it is a fexible framework for organizing the Nodes that come with the default installation
of Dynamo - and it's even better down the road when we start extending this base functionality
with Custom Nodes and additional Packages.
Naming Conventions
The hierarchy of each library is refected in the Name of Nodes added to the Workspace, which
we can also use in the Search Field or with Code Blocks (which use the Dynamo textual
language). Beyond using key words to try to fnd Nodes, we can type the hierarchy separated
with a period.
Typing in different portions of the Node's place in the Library hierarchy in the
library.category.nodeName format returns different results:
1. library.category.nodeName
2. category.nodeName
3. nodeName or keyword
Typically the Name of the Node in the Workspace will be rendered in the category.nodeName
format, with some notable exceptions particularly in the Input and View Categories. Beware of
similarly named Nodes and note the category difference:
1. Nodes from most libraries will include the category format
2. Point.ByCoordinates and UV.ByCoordinates have the same Name but come from
different categories
3. Notable exceptions include Built-in Functions, Core.Input, Core.View, and Operators
Input
Input Nodes are the primary means for the User of our Visual Program - be that yourself or
someone else - to interface with the key parameters. Here are the Nodes available in the Input
Category of the Core Library:
1. Boolean
2. Number
3. String
4. Number Slider
5. Integer Slider
6. Directory Path
7. File Path
Watch
The Watch Nodes are essential to managing the data that is fowing through your Visual
Program. While you can view the result of a Node through the Node data preview, you may
want to keep it revealed in a Watch Node or see the geometry results through a Watch3D
Node. Both of these are found in the View Category in the Core Library.
Tip: Occasionally the 3D Preview can be distracting when your Visual Program contains a
lot of Nodes. Consider unchecking the Showing Background Preview option in the
Settings Menu and using a Watch3D Node to preview your geometry.
1. Watch - Note that when you select an item in the Watch Node it will be tagged in the
Watch3D and 3D Previews
2. Watch3D - Grab the bottom right grip to resize and navigate with you mouse the
same way you would in the 3D Preview
Code Block
Code Block Nodes can be used to defne a block of code with lines separated by semi-colons.
This can be as simple as X/Y . We can also use Code Blocks as a short cut to defning a
Number Input or call to another Node's functionality. The syntax to do so follows the Naming
Convention of the Dynamo textual language, DesignScript, and is covered in Section 7.2. Let's
try to make a Circle with this shortcut:
Working within a Visual Programming process can be a powerful creative activity, but very
quickly the Program Flow and key user inputs can be obscured by complexity and/or layout of
the Workspace. Let's review some best practices for managing your program.
Alignment
Once we have added more than a few Nodes to the Workspace, we may want to re-organize
the layout of the Nodes for clarity's sake. By selecting more than one Node and right-clicking
on the Workspace, the pop up window includes an Align Selection menu with justifcation and
distribution options in X and Y.
Notes
With some experience, we may be able to "read" the Visual Program by reviewing the Node
Names and following the Program Flow. For users of all experience levels, it is also good
practice to include plain language labels and descriptions. Dynamo has a Notes Node with an
editable text feld to do so. We can add Notes to the Workspace in two ways:
Once the Note is added to the Workspace a text feld will pop up allowing us to edit the text in
the Note. After they are created, we can edit the Note by double-clicking or right-clicking the
Note Node.
Grouping
When our Visual Program gets big, it is helpful to identify the larger steps that will be executed.
We can highlight larger collections of Nodes with a Group to label them with a colored
rectangle in the background and a title. There are three ways to make a Group with more than
one Node selected:
1. Browse to the menu Edit > Create Group
2. Use the keyboard shortcut Ctrl+G
3. Right-click on the Workspace and select "Create Group"
Once a Group is created we can edit its settings, such as the title and color.
Tip: Using both Notes and Groups is an effective way to annotate your fle and increase
readability.
Here's our program from Section 2.4 with Notes and Groups added:
1. Note: "Grid Parameters"
2. Note: "Grid Points"
3. Group: "Create a Grid of Points"
4. Group: "Create an Attractor Point"
5. Note: "Calibrate Distance Values"
6. Note: "Variable Grid of Circles"
THE BUILDING BLOCKS OF PROGRAMS
Once we are ready to dive deeper into developing Visual Programs, we will need a deeper
understanding of the building blocks we will use. This chapter introduces fundamental
concepts around data - the stuff that travels through the Wires of our Dynamo program.
Data
Data is the stuff of our programs. It travels through Wires, supplying inputs for Nodes where it
gets processed into a new form of output data. Let's review the defnition of data, how it's
structured, and begin using it in Dynamo.
What is Data?
Data is a set of values of qualitative or quantitative variables. The simplest form of data is
numbers such as 0 , 3.14 , or 17 . But data can also be of a number of different types: a
variable representing changing numbers ( height ); characters ( myName ); geometry ( Circle );
or a list of data items ( 1,2,3,5,8,13,... ). We need data to add to the input Ports of Dynamo's
Nodes - we can have data without actions but we need data to process the actions that our
Nodes represent. When we've added a Node to the Workspace, if it doesn't have any inputs
supplied, the result will be a function, not the result of the action itself.
1. Simple Data
2. Data and Action (A Node) successfully executes
3. Action (A Node) without Data Inputs returns a generic function
Beware of Nulls
The 'null' type represents the absence of data. While this is an abstract concept, you will
likely come across this while working with Visual Programming. If an action doesn't create a
valid result, the Node will return a null. Testing for nulls and removing nulls from data structure
is a crucial part to creating robust programs.
1. A Number Sequence node defnes a list of numbers by using a start, amount, and
step input. With these nodes, we've created two separate lists of ten numbers, one
which ranges from 100-109 and another which ranges from 0-9.
2. The List.GetItemAtIndex node selects an item in a list at a specifc index. When
choosing 0, we get the frst item in the list (100 in this case).
3. Applying the same process to the second list, we get a value of 0, the frst item in the
list.
4. Now we merge the two lists into one by using the List.Create node. Notice that the
node creates a list of lists. This changes the structure of the data.
5. When using List.GetItemAtIndex again, with index set to 0, we get the frst list in the
list of lists. This is what it means to treat a list as an item, which is somewhat different
from other scripting languages. We will get more advanced with list manipulation and
data structure in later chapters.
The key concept to understand about data hierarchy in Dynamo: with respect to data structure,
lists are regarded as items. In other words, Dynamo functions with a top-down process for
understanding data structures. What does this mean? Let's walk through it with an example.
In this frst example, we assemble a shelled cylinder which walks through the geometry
hierarchy discussed in this section.
1. Point.ByCoordinates - after adding the node to canvas, we see a point at the origin of
the Dynamo preview grid. The default values of the x,y, and z inputs are 0.0, giving
us a point at this location.
1. Plane.ByOriginNormal - The next step in the geometry hierarchy is a plane. There are
several ways to construct a plane, and we are using an origin and normal for the
input. The origin is the point node created in the previous step.
2. Vector.ZAxis - this is a unitized vector in the z direction. Notice there are not inputs,
only a vector of [0,0,1] value. We use this as the normal input for the
Plane.ByOriginNormal node. This gives us a rectangular plane in the Dynamo
preview.
1. Circle.ByPlaneRadius - Stepping up the hierarchy, we now create a curve from the
plane in our previous step. After plugging into the node, we get a circle at the origin.
The default radius on the node is value of 1.
1. Curve.Extrude - Now we make this thing pop by giving it some depth and going in the
third dimension. This node creates a surface from a curve by extruding it. The default
distance on the node is 1, and we should see a cylinder in the viewport.
1. Surface.Thicken - This node gives us a closed solid by offsetting the surface a given
distance and closing the form. The default thickness value is 1, and we see a shelled
cylinder in the viewport in line with these values.
1. Number Slider - Rather than using the default values for all of these inputs, let's add
some parametric control to the model.
2. Domain Edit - after adding the number slider to the canvas, click the caret in the top
left to reveal the domain options.
3. Min/Max/Step - change the min, max, and step values to 0,2, and 0.01 respectively.
We are doing this to control the size of the overall geometry.
1. Number Sliders - In all of the default inputs, let's copy and paste this number slider
(select the slider, hit Ctrl+C, then Ctrl+V) several times, until all of the inputs with
defaults have a slider instead. Some of the slider values will have to be larger than
zero to get the defnition to work (ie: you need an extrusion depth in order to have a
surface to thicken).
We've now created a parametric shelled cylinder with these sliders. Try to fex some of these
parameters and see the geometry update dynamically in the Dynamo viewport.
1. Number Sliders - taking this a step further, we've added a lot of sliders to the canvas,
and need to clean up the interface of the tool we just created. Right click on one
slider, select "Rename..." and change each slider to the appropriate name for its
parameter. You can reference the image above for names.
At this point, we've created an awesome thickening cylinder thing. This is one object currently,
let's look at how to create an array of cylinders that remains dynamically linked. To do this,
we're going to create a list of cylinders, rather than working with a single item.
1. Addition (+) - Our goal is to add a row of cylinders next to the cylinder we've created.
If we want to add one cylinder adjacent to the current one, we need to consider both
radius of the cylinder and the thickness of its shell. We get this number by adding the
two values of the sliders.
This step is more involved so let's walk through it slowly: the end goal is to create a list of
numbers which defne the locations of each cylinder in a row.
1. Multiplication - First, we want to multiply the value from the previous step by 2. The
value from the previous step represents a radius, and we want to move the cylinder
the full diameter.
2. Number Sequence - we create an array of numbers with this node. The frst input is
the multiplication node from the previous step into the step value. The start value can
be set to 0.0 using a number node.
3. Integer Slider - For the amount value, we connect an integer slider. This will defne
how many cylinders are created.
4. Output - This list shows us the distance moved for each cylinder in the array, and is
parametrically driven by the original sliders.
1. This step is simple enough - plug the sequence defned in the previous step into the x
input of the original Point.ByCoordinates. This will replace the slider pointX which we
can delete. We now see an array of cylinders in the viewport (make sure the integer
slider is larger than 0).
The chain of cylinders is still dynamically linked to all of the sliders. Flex each slider to
watch the defnition update!
Math
If the simplest form of data is numbers, the easiest way to relate those numbers is through
Mathematics. From simple operators like divide to trigonometric functions, to more complex
formulas, Math is a great way to start exploring numeric relationships and patterns.
Arithmetic Operators
Operators are a set of components that use algebraic functions with two numeric input values,
which result in one output value (addition, subtraction, multiplication, division, etc.). These can
be found under Operators>Actions.
Parametric Formula
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Building Blocks of Programs - Math.dyn. A full list of example fles can be found in
the Appendix.
From Operators, the next logical step is to combine operators and variables to form a more
complex relationship through Formulas. Let's make a Formula that can be controlled by input
parameters, like sliders.
1. Number Sequence: defne a number sequence based on three inputs: start, amount
and step. This sequence represents the 't' in the parametric equation, so we want to
use a list that's large enough to defne a spiral.
The step above has created a list of numbers to defne the parametric domain. The golden
spiral is defned as the equation: = and
= . The group of
Nodes below represent this equation in visual programming form.
When stepping through the group of Nodes, try to pay attention to the parallel between the
visual program and written equation.
1. Number Slider: Add two number sliders to the canvas. These sliders will represent
the a and the b variables of the parametric equation. These represent a constant
which is fexible, or parameters which we can adjust towards a desired outcome.
2. * : The multiplication Node is represented by an asterisk. We'll use this repeatedly to
connect multiplying variables
3. Math.RadiansToDegrees: The 't' values need to be translated to degrees for their
evaluation in the trigonometric functions. Remember, Dynamo defaults to degrees for
evaluating these functions.
4. Math.Pow: as a function of the 't' and the number 'e' this creates the Fibonacci
sequence.
5. Math.Cos and Math.Sin: These two trigonmetric functions will differentiate the x-
coordinate and the y-coordinate, respectively, of each parametric point.
6. Watch: We now see that our output is two lists, these will be the x and y coordinates
of the points used to generate the spiral.
1. Point.ByCoordinates: Connect the upper multiplication node into the 'x' input and the
lower into the 'y' input. We now see a parametric spiral of points on the screen.
We've now completed the Fibonacci Spiral! Let's take this further into two separate exercises
from here, which we'll call the Nautilus and the Sunfower. These are abstractions of natural
systems, but the two different applications of the Fibonacci spiral will be well represented.
1. As a jumping-off point, let's start with the same step from the previous exercise:
creating a spiral array of points with the Point.ByCoordinates Node.
1. Polycurve.ByPoints: Again, this is the Node from the pervious exercise, which we'll
use as a reference.
2. Circle.ByCenterPointRadius: We'll use a circle Node here with the same inputs as the
previous step. The radius value defaults to 1.0, so we see an immediate output of
circles. It becomes immediately legible how the points diverge further from the origin.
1. Again, as a jumping-off point, let's start with the same step from the previous
exercise: creating a spiral array of points with the Point.ByCoordinates Node.
1. Geometry.Rotate: There are several Geometry.Rotate options; be certain you've
chosen the Node with geometry,basePlane, and degrees as its inputs. Connect
Point.ByCoordinates into the geometry input.
2. Plane.XY: Connect to the basePlane input. We will rotate around the origin, which is
the same location as the base of the spiral.
3. Number Range: For our degree input, we want to create multiple rotations. We can
do this quickly with a Number Range component. Connect this into the degrees input.
4. Number: And to defne the range of numbers, add three number nodes to the canvas
in vertical order. From top to bottom, assign values of 0.0,360.0, and 120.0
respectively. These are driving the rotation of the spiral. Notice the output results from
the Number Range node after connecting the three number nodes to the Node.
Our output is beginning to resemble a whirlpool. Let's adjust some of the Number Range
parameters and see how the results change:
1. Change the step size of the Number Range node from 120.0 to 36.0. Notice that this
is creating more rotations and is therefore giving us a denser grid.
1. Change the step size of the Number Range node from 36.0 to 3.6. This now gives us
a much denser grid, and the directionality of the spiral is unclear. Ladies and
gentlemen, we've created a sunfower.
Logic
Logic, or more specifcally, Conditional Logic, allows us to specify an action or set of actions
based on a test. After evaluating the test, we will have a Boolean value representing True or
False that we can use to control the Program Flow.
Booleans
Numeric variables can store a whole range of different numbers. Boolean variables can only
store two values referred to as True or False, Yes or No, 1 or 0. We rarely use booleans to
perform calculations because of their limited range.
Conditional Statements
The "If" statement is a key concept in programming: "If this is true, then that happens,
otherwise something else happens. The resulting action of the statement is driven by a
boolean value. There are multiple ways to defne an "If" statement in Dynamo:
Let's go over a brief example on each of these three nodes in action using the conditional "If"
statement:
In this image, the boolean is set to true, which means that the result is a string reading:
"this is the result if true". The three Nodes creating the If statement are working identically
here.
Again, the Nodes are working identically. If the boolean is changed to false, our result is
the number Pi, as defned in the original If statement.
Filtering a List
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Building Blocks of Programs - Logic.dyn. A full list of example fles can be found in
the Appendix.
Let's use logic to separate a list of numbers into a list of even numbers and a list of odd
numbers.
1. Number Range - add a number range to the canvas.
2. Numbers - add three number nodes to the canvas. The value for each number node
should be: 0.0 for start, 10.0 for end, and 1.0 for step.
3. Output - our output is a list of 11 numbers ranging from 0-10.
4. Modulo (%)- Number Range into x and 2.0 into y. This calculates the remainder for
each number in the list divided by 2. The output from this list gives us a list of values
alternating between 0 and 1.
5. Equality Test (==) - add an equality test to the canvas. Plug modulo output into the x
input and 0.0 into the y input.
6. Watch - The output of the equality test is a list of values alternating between true and
false. These are the values used to separate the items in the list. 0 (or true)
represents even numbers and (1, or false) represents odd numbers.
7. List.FilterByBoolMask - this Node will flter the values into two different lists based on
the input boolean. Plug the original number range into the list input and the equality
test output into the mask input. The in output represents true values while the out
output represents false values.
8. Watch - as a result, we now have a list of even numbers and a list of odd numbers.
We've used logical operators to separate lists into patterns!
We'll jump off from the previous exercise with the same Nodes. The only exceptions (in
addition to changing the format are):
Let's begin by connecting the Nodes together as shown in the image above. This group of
Nodes represents a parametric equation to defne a line curve. A few notes:
1. The frst slider should have a min of 1, a max of 4, and a step of 0.01.
2. The second slider should have a min of 0, a max of 1, and a step of 0.01.
3. PolyCurve.ByPoints - if the above Node diagram is copied, the result is a sine curve
in the Dynamo Preview viewport.
The method here for the inputs: use number nodes for more static properties and number
sliders on the more fexible ones. We want to keep the original number range that we're
defning in the beginning of this step. However, the sine curve that we create here should have
some fexibility. We can move these sliders to watch the curve update its frequency and
amplitude.
We're going to jump around a bit in the defnition, so let's look at the end result so that we
can reference what we're getting at. The frst two steps are made separately, we now want
to connect the two. We'll use the base sine curve to drive the location of the zipper
components, and we'll use the true/false logic to alternate between little boxes and larger
boxes.
1. Math.RemapRange - Using the number sequence created in step 01, let's create a
new series of numbers by remapping the range. The original numbers from step 01
range from 0-100. These numbers range from 0 to 1 by the newMin and newMax
inputs respectively.
1. Number Slider - stepping back to the beginning of the defnition, we can fex the
number slider and watch the zipper update. The top row of images represents a
range values for the top number slider. This is the frequency of the wave.
2. Number Slider - the bottom row of images represents a range of values for the bottom
slider. This is the amplitude of the wave.
Strings
Creating Strings
Strings can be used for a wide range of applications, including defning custom parameters,
annotating documentation sets, and parsing through text-based data sets. The string Node is
located in the Core>Input Category.
The sample Nodes above are strings. A number can be represented as a string, as can a
letter, or an entire array of text.
Querying Strings
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Building Blocks of Programs - Strings.dyn. A full list of example fles can be found
in the Appendix.
You can parse through large amounts of data quickly by querying strings. We'll talk about
some basic operations which can speed up a workfow and help for software interoperability.
The image below considers a string of data coming from an external spreadsheet. The string
represents the vertices of a rectangle in the XY-Plane. Let's break down some string split
operations in miniature exercise:
1. The ";" separator splits each vertex of the rectangle. This creates a list with 4 items
for each vertex.
1. By hitting the "+" in the middle of the Node, we create new separator.
2. Add a "," string to the canvas and plug in to the new separator input.
3. Our result is now a list of ten items. The Node frst splits based on separator0, then
based on separator1.
While the list of items above may look like numbers, they are still regarded as individual strings
in Dynamo. In order to create points, their data type needs to be converted from a string to a
Number. This is done with the String.ToNumber Node
1. This Node is straightforward. Plug the String.Split results into the input. The output
doesn't look different, but the data type is now a number instead of a string.
1. With some basic additional operations, we now have a rectangle drawn at the origin
based on the original string input.
Manipulating Strings
Since a string is a generic text object, they host a wide range of applications. Let's take a look
at some of the major actions in the Core>String Category in Dynamo:
This is a method of merging two strings together in order. This takes each literal string in a list
and creates one merged string.
1. Add or subtract strings to the concatenation by clicking the +/- buttons in the center of
the Node.
2. The output gives one concatenated string, with spaces and punctuation included.
The join method is very similar to concatenate, except it has an added layer of punctuation.
If you've worked in Excel, you may have come across a CSV fle. This stands for comma-
separated values. One could use a comma (or in this case, two dashes) as the separator with
the join Node in order to create a similar data structure:
1. The separator input allows one to create a string which divides the joined strings.
Now, we want to drive home the repetition of the stanza by merging the two lines together.
When viewing the output of the previous step, we notice that there are two items in the
list:
1. Using two List.GetItemAtIndex Nodes, we can isolate the items using the values of 0
and 1 as the index input.
2. The output for each Node gives us, in order, the fnal two lines.
To merge these two items into one, we use the String.Join Node:
This may seem like a lot of work to isolate the last two lines; and it's true, string operations
often require some up front work. But they are scalable, and they can be applied to large
datasets with relative ease. If you are working parametrically with spreadsheets and
interoperability, be sure to keep string operations in mind.
Color
Color is a great data type for creating compelling visuals as well as for rendering difference in
the output from your Visual Program. When working with abstract data and varying numbers,
sometimes it's diffcult to see what's changing and to what degree. This is a great application
for colors.
Creating Colors
Colors in Dynamo are created using ARGB inputs.This corresponds to the Alpha, Red, Green,
and Blue channels. The alpha represents the transparency of the color, while the other three
are used as primary colors to generate the whole spectrum of color in concert.
The colors in the table below correspond to the HSB color space. Dividing the color into hue,
saturation, and brightness is arguably more intuitive for how we interpret color: What color
should it be? How colorful should it be? And how light or dark should the color be? This is the
breakdown of hue, saturation, and brightness respectively.
Color Range
The color range is similar to the Remap Range Node from section 4.2: it remaps a list of
numbers into another domain. But instead of mapping to a number domain, it maps to a color
gradient based on input numbers ranging from 0 to 1.
The current Node works well, but it can be a little awkward to get everything working the frst
time around. The best way to become familiar with the color gradient is to test it out
interactively. Let's do a quick exercise to review how to setup a gradient with output colors
corresponding to numbers.
1. Defne three colors: Using a code block node, defne red, green, and blue by plugging
in the appropriate combinations of 0 and 255.
2. Create list: Merge the three colors into one list.
3. Defne Indices: Create a list to defne the grip positions of each color (ranging from 0
to 1). Notice the value of 0.75 for green. This places the green color 3/4 of the way
across the horizontal gradient in the color range slider.
4. Code Block: Input values (between 0 and 1) to translate to colors.
Color Preview
The Display.ByGeometry Node gives us the ability to color geometry in the Dynamo viewport.
This is helpful for separating different types of geometry, demonstrating a parametric concept,
or defning an analysis legend for simulation. The inputs are simple: geometry and color. To
create a gradient like the image above, the color input is connected to the color range Node.
Color Exercise
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Building Blocks of Programs - Color.dyn. A full list of example fles can be found in
the Appendix.
This exercise focuses on controlling color parametrically in parallel with geometry. The
geometry is a basic helix, which we defne below using the Code Block (3.2.3). This is a quick
and easy way to create a parametric function; and since our focus is on color (rather than
geometry), we use the code block to effciently create the helix without cluttering the canvas.
We will use the code block more frequently as the primer moves to more advanced material.
1. Code Block: Defne the two code blocks with the formulas above. This is a quick
parametric method for creating a spiral.
2. Point.ByCoordinates:Plug the three outputs from the code block into the coordinates
for the Node.
We now see an array of points creating a helix. The next step is to create a curve through the
points so that we can visualize the helix.
1. PolyCurve.ByPoints: Connect the Point.ByCoordinates output into the points input for
the Node. We get a helical curve.
2. Curve.PointAtParameter: Connect the PolyCurve.ByPoints output into the curve
input. The purpose of this step is to create a parametric attractor point which slides
along the curve. Since the curve is evaluating a point at parameter, we'll need to input
a param value between 0 and 1.
3. Number Slider: After adding to the canvas, change the min value to 0.0, the max
value to 1.0, and the step value to .01. Plug the slider output into the param input for
Curve.PointAtParameter. We now see a point along the length of the helix,
represented by a percentage of the slider (0 at the start point, 1 at the end point).
With the reference point created, we now compare the distance from the reference point to the
original points defning the helix. This distance value will drive geometry as well as color.
1. Geometry.DistanceTo: Connect Curve.PointAtParameter output into the input.
Connect Point.ByCoordinates into the *geometry input.
2. Watch: The resultant output shows a list of distances from each helical point to the
reference point along the curve.
Our next step is to drive parameters with the list of distances from the helical points to the
reference point. We use these distance values to defne the radii of a series of spheres along
the curve. In order to keep the spheres a suitable size, we need to remap the values for
distance.
1. Math.RemapRange: Connect Geometry.DistanceTo output into the numbers input.
2. Code Block: connect a code block with a value of 0.01 into the newMin input and a
code block with a value of 1 into the newMax input.
3. Watch: connect the Math.RemapRange output into one Node and the
Geometry.DistanceTo output into another. Compare the results.
This step has remapped the list of distance to be a smaller range. We can edit the newMin and
newMax values however we see ft. The values will remap and will have the same distribution
ratio across the domain.
1. Sphere.ByCenterPointRadius: connect the Math.RemapRange output into the radius
input and the original Point.ByCoordinates output into the centerPoint input.
1. Number Slider: change the value of the number slider and watch the size of the
spheres update. We now have a parametric jig.
The size of the spheres demonstrates the parametric array defned by a reference point along
the curve. Let's use the same concept for the sphere radius to drive their color.
1. Color Range: Add top the canvas. When hovering over the value input, we notice that
the numbers requested are between 0 and 1. We need to remap the numbers from
the Geometry.DistanceTo output so that they are compatible with this domain.
2. Sphere.ByCenterPointRadius: For the time being, let's disable the preview on this
Node (Right Click > Preview)
1. Math.RemapRange: This process should look familiar. Connect the
Geometry.DistanceTo output into the numbers input.
2. Code Block: Similar to an earlier step, create a value of 0 for the newMin input and a
value of 1 for the newMax input. Notice that we are able to defne two outputs from
one code block in this case.
3. Color Range: Connect the Math.RemapRange output into the value input.
1. Color.ByARGB: This is what we'll do to create two colors. While this process may
look awkward, it's the same as RGB colors in another software, we're just using
visual programming to do it.
2. Code Block: create two values of 0 and 255. Plug the two outputs into the two
Color.ByARGB inputs in agreement with the image above (or create your favorite two
colors).
3. Color Range: The colors input requests a list of colors. We need to create this list
from the two colors created in the previous step.
4. List.Create: merge the two colors into one list. Plug the output into the colors input for
Color Range.
1. Display.ByGeometryColor: Connect Sphere.ByCenterPointRadius into the geometry
input and the Color Range into the color input. We now have a smooth gradient
across the domain of the curve.
If we change the value of the number slider from earlier in the defnition, the colors and
sizes update. Colors and radius size are directly related in this case: we now have a visual
link between two parameters!
Color On Surfaces
The Display.BySurfaceColors node gives us the ability to map data across a surface using
color! This functionality introduces some exciting possibilities for visualizing data obtained
through discrete analysis like solar, energy, and proximity. Applying color to a surface in
Dynamo is similar to applying a texture to a material in other CAD environments. Let's
demonstrate how to use this tool in the brief exercise below.
1. This Group of nodes is creating points along the Z-axis then displacing them based
on sine and cosine functions. The two point lists are then used to generate NURBS
curves.
2. Surface.ByLoft: generate an interpolated surface between the list of NURBS curves.
1. File Path: select an image fle to sample for pixel data downstream
2. use File.FromPath to convert the fle path to a fle then pass into
Image.ReadFromFile to output an image for sampling
3. Image.Pixels: input an image and provide a sample value to use along the x and y
dimensions of the image.
4. Slider: provide sample values for Image.Pixels
5. Display.BySurfaceColors: map array of color values across surface along X and Y
respectively
Close-up preview of the output surface with resolution of 400x300 samples
GEOMETRY FOR COMPUTATIONAL DESIGN
As a Visual Programming environment, Dynamo enables you to craft the way that data is
processed. Data is numbers or text, but so is Geometry. As understood by the Computer,
Geometry - or sometimes called Computational Geometry - is the data we can use to create
beautiful, intricate, or performance-driven models. To do so, we need to understand the ins
and outs of the various types of Geometry we can use.
Geometry Overview
Geometry is the language for design. When a programming language or environment has a
geometry kernel at its core, we can unlock the possibilities for designing precise and robust
models, automating design routines, and generating design iterations with algorithms.
The Basics
Geometry, traditionally defned, is the study of shape, size, relative position of fgures, and the
properties of space. This feld has a rich history going back thousands of years. With the
advent and popularization of the computer, we gained a powerful tool in defning, exploring,
and generating geometry. It is now so easy to calculate the result of complex geometric
interactions, the fact that we are doing so is almost transparent.
If you're curious to see how diverse and complex geometry can get using the power of
your computer, do a quick web search for the Stanford Bunny - a canonical model used to
test algorithms.
Understanding geometry in the context of algorithms, computing, and complexity, may sound
daunting; however, there are a few key, and relatively simple, principles that we can establish
as fundamentals to start building towards more advanced applications:
1. Geometry is Data - to the computer and Dynamo, a Bunny not all that different from a
number.
2. Geometry relies on Abstraction - fundamentally, geometric elements are described by
numbers, relationships, and formulas within a given spatial coordinate system
3. Geometry has a Hierarchy - points come together to make lines, lines come together to
make surfaces, and so on
4. Geometry simultaneously describes both the Part and the Whole - when we have a curve,
it is both the shape as well as all the possible points along it
In practice, these principles mean that we need to be aware of what we are working with (what
type of geometry, how was it created, etc.) so that we can fuidly compose, decompose, and
recompose different geometries as we develop more complex models.
Dimensionality is a convenient way to start categorizing Geometry but it's not necessarily the
best. After all, we don't model with only Points, Lines, Planes, and Boxes - what if I want
something curvy? Furthermore, there is a whole other category of Geometric types that are
completely abstract ie. they defne properties like orientation, volume, or relationships between
parts. We can't really grab a hold of a Vector so how do we defne it relative to what we see in
space? A more detailed categorization of the geometric hierarchy should accommodate the
difference between Abstract Types or "Helpers," each of which we can group by what they help
do and types that help describe the shape of model elements.
Additionally, making models in Dynamo and connecting the preview of what we see in the
Background Preview to the fow of data in our graph should become more intuitive over time.
1. Note the assumed coordinate system rendered by the grid and colored axes
2. Selected Nodes will render the corresponding geometry (if the Node creates
geometry) in the background the highlight color
Download the example fle that accompanies this image (Right click and "Save Link
As..."): Geometry for Computational Design - Geometry Overview.dyn. A full list of
example fles can be found in the Appendix.
1. Dynamo allows you to import fles - try using a CSV for point clouds or SAT for bringing in
surfaces
2. When working with Revit, we can reference Revit elements to use in Dynamo
3. The Dynamo Package Manager offers additional functionality for extended geometry types
and operations - check out the Mesh Toolkit package
Vectors, Planes, and Coordinate Systems
Vectors, Planes, and Coordinate Systems make up the primary group of Abstract Geometry
Types. They help us defne location, orientation, and the spatial context for other geometry that
describe shapes. If I say that I'm in New York City at 42nd Street and Broadway (Coordinate
System), standing on the street level (Plane), looking North (Vector), I've just used these
"Helpers" to defne where I am. The same goes for a phone case product or a skyscraper - we
need this context to develop our model.
What's a Vector?
A vector is a geometric quantity describing Direction and Magnitude. Vectors are abstract; ie.
they represent a quantity, not a geometrical element. Vectors can be easily confused with
Points because they both are composed of a list of values. There is a key difference though:
Points describe a position in a given coordinate system while Vectors describe a relative
difference in position which is the same as saying "direction."
If the idea of relative difference is confusing, think of the Vector AB as "I'm standing at Point A,
looking toward Point B." The direction, from here (A) to there (B), is our Vector.
Breaking down Vectors further into their parts using the same AB notation:
1. The Start Point of the Vector is called the Base.
2. The End Point of the Vector is called the Tip or the Sense.
3. Vector AB is not the same as Vector BA - that would point in the opposite direction.
If you're ever in need of comic relief regarding Vectors (and their abstract defnition), watch the
classic comedy Airplane and listen for the oft-quoted tongue-in cheek line:
Vectors are a key component to our models in Dynamo. Note that, because they are in the
Abstract category of "Helpers," when we create a Vector, we won't see anything in the
Background Preview.
1. We can use a line as a stand in for a Vector preview.
Download the example fle that accompanies this image (Right click and "Save Link
As..."): Geometry for Computational Design - Vectors.dyn. A full list of example fles can
be found in the Appendix.
What's a Plane?
Planes are two-dimensional abstract "Helpers." More specifcally, Planes are conceptually
“fat,” extending infnitely in two directions. Usually they are rendered as a smaller rectangle
near their origin.
You might be thinking, "Wait! Origin? That sounds like a Coordinate System... like the one I
use to model in my CAD software!"
And you're correct! Most modeling software take advantage of construction planes or "levels"
to defne a local two-dimentional context to draft in. XY, XZ, YZ -or- North, Southeast, Plan
might sound more familiar. These are all Planes, defning an infnite "fat" context. Planes don't
have depth, but they do help us describe direction as well - each Plane has an Origin, X
Direction, Y Direction, and a Z (Up) Direction.
1. Although they are abstract, Planes do have an origin position so we can locate them
in space.
2. In Dynamo, Planes are rendered in the Background Preview.
Download the example fle that accompanies this image (Right click and "Save Link
As..."): Geometry for Computational Design - Planes.dyn. A full list of example fles can be
found in the Appendix.
There are other, however, alternative Coordinate Systems such as Cylindrical or Spherical. As
we will see in later sections, Coordinate Systems can also be applied to other Geometry types
to defne a position on that geometry.
Add alternative coordinate systems - cylindrical, spherical
1. Although they are abstract, Coordinate Systems also have an origin position so we
can locate them in space.
2. In Dynamo, Coordinate Systems are rendered in the Background Preview as a point
(origin) and lines defning the axes (X is red, Y is green, and Z is blue following
convention).
Download the example fle that accompanies this image (Right click and "Save Link
As..."): Geometry for Computational Design - Coordinate System.dyn. A full list of example
fles can be found in the Appendix.
Points
If Geometry is the language of a model, then Points are the alphabet. Points are the foundation
upon which all other geometry is created - we need at least two Points to create a Curve, we
need at least three Points to make a Polygon or a Mesh Face, and so on. Defning the position,
order, and relationship among Points (try a Sine Function) allows us to defne higher order
geometry like things we recognize as Circles or Curves.
What's a Point?
A Point is defned by nothing more than one or more values called coordinates. How
many coordinate values we need to defne the Point depends upon the Coordinate
System or context in which it resides. The most common kind of Point in Dynamo
exists in our three-dimensional World Coordinate System and has three coordinates
[X,Y,Z].
Point as Coordinates
Points can exist in a two-dimensional Coordinate System as well. Convention has different
letter notation depending upon what kind of space we are working with - we might be using
[X,Y] on a Plane or [U,V] if we are on a surface.
Although it might seem counter intuitive, Parameters for both Curves and Surfaces are
continuous and extend beyond the edge of the given geometry. Since the shapes that defne
the Parameter Space reside in a three-dimensional World Coordinate System, we can always
translate a Parametric Coordinate into a "World" Coordinate. The point [0.2, 0.5] on the surface
for example is the same as point [1.8, 2.0, 4.1] in world coordinates.
1. Point in assumed World XYZ Coordinates
2. Point relative to a given Coordinate System (Cylindrical)
3. Point as UV Coordinate on a Surface
Download the example fle that accompanies this image (Right click and "Save Link
As..."): Geometry for Computational Design - Points.dyn. A full list of example fles can be
found in the Appendix.
Curves
Curves are the frst Geometric Data Type we've covered that have a more familiar set of shape
descriptive properties - How curvey or straight? How long or short? And remember that Points
are still our building blocks for defning anything from a line to a spline and all the Curve types
in between.
1. Line
2. Polyline
3. Arc
4. Circle
5. Ellipse
6. NURBS Curve
7. Polycurve
What's a Curve?
The term Curve is generally a catch-all for all different sort of curved (even if straight) shapes.
Capital "C" Curve is the parent categorization for all of those shape types - Lines, Circles,
Splines, etc. More technically, a Curve describes every possible Point that can be found by
inputting "t" into a collection of functions, which may range from the simple ( x = -1.26*t, y =
t ) to functions involving calculus. No matter what kind of Curve we are working with, this
Parameter called "t" is a property we can evaluate. Furthermore, regardless of the look of the
shape, all Curves also have a start point and end point, which coincidentally align with the
minimum and maximum t values used to create the Curve. This also helps us understand its
directionality.
It's important to note that Dynamo assumes that the domain of "t" values for a Curve is
understood to be 0.0 to 1.0.
All Curves also possess a number of properties or characteristics which can be used to
describe or analyze them. When the distance between the start and end points is zero, the
curve is "closed." Also, every curve has a number of control-points, if all these points are
located in the same plane, the curve is "planar." Some properties apply to the curve as a
whole, while others only apply to specifc points along the curve. For example, planarity is a
global property while a tangent vector at a given t value is a local property.
Lines
Lines are the simplest form of Curves. They may not look curvy but they are in fact Curves -
just without any curvature. There are a few different ways to create Lines, the most intuitive
being from Point A to Point B. The shape of the Line AB will be drawn between the points but
mathematically it extends infnitely in both directions.
When we connect two Lines together, we have a Polyline. Here we have a straightforward
representation of what a Control Point is. Editing any of these point locations will change the
shape of the Polyline. If the Polyline is closed, we have a Polygon. If the Polygon's edge
lengths are all equal, it is described as regular.
Arcs, Circles, Ellipse Arcs, and Ellipses
As we add more complexity to the Parametric Functions that defne a shape, we can take one
step further from a Line to create an Arc, Circle, Ellipse Arc, or Ellipse by describing one or two
radii. The differences between the Arc version and the Circle or Ellipse is only whether or not
the shape is closed.
NURBS + Polycurves
NURBS (Non-uniform Rational Basis Splines) are mathematical representations that can
accurately model any shape from a simple two dimensional Line, Circle, Arc, or Rectangle to
the most complex three-dimensional free-form organic Curve. Because of their fexibility
(relatively few control points, yet smooth interpolation based on Degree settings) and precision
(bound by a robust math), NURBS models can be used in any process from illustration and
animation to manufacturing.
Degree: The Degree of the Curve determines the range of infuence the Control Points have on
a Curve; where the higher the degree, the larger the range. The Degree is a positive whole
number. This number is usually 1, 2, 3 or 5, but can be any positive whole number. NURBS
lines and polylines are usually Degree 1 and most free-form Curves are Degree 3 or 5.
Control Points: The Control Points are a list of at least Degree+1 Points. One of the easiest
ways to change the shape of a NURBS Curve is to move its Control Points.
Weight: Control Points have an associated number called a Weight. Weights are usually
positive numbers. When a Curve’s Control Points all have the same weight (usually 1), the
Curve is called non-rational, otherwise the Curve is called rational. Most NURBS curves are
non-rational.
Knots: Knots are a list of (Degree+N-1) numbers, where N is the number of Control Points. The
Knots are used together with the weights to control the infuence of the Control Points on the
resulting Curve. One use for Knots is to create kinks at certain points in the curve.
1. Degree = 1
2. Degree = 2
3. Degree = 3
Note that the higher the degree value, the more Control Points are used to interpolate the
resulting Curve.
Let's make a sine curve in Dynamo using two different methods to create NURBS Curves to
compare the results.
1. NurbsCurve.ByControlPoints uses the List of Points as Control Points
2. NurbsCurve.ByPoints draws a Curve through the List of Points
Download the example fle that accompanies this image (Right click and "Save Link
As..."): Geometry for Computational Design - Curves.dyn. A full list of example fles can be
found in the Appendix.
Surfaces
As we move from using Curves to using Surfaces in a model, we can now begin to represent
objects we see in our three dimensional world. While Curves are not always planar ie. they are
three dimensional, the space they defne is always bound to one dimension. Surfaces give us
another dimension and a collection of additional properties we can use within other modeling
operations.
What's a Surface?
A Surface is a mathematical shape defned by a function and two parameters, Instead of t
for Curves, we use U and V to describe the corresponding parameter space. This means
we have more geometrical data to draw from when working with this type of Geometry. For
example, Curves have tangent vectors and normal planes (which can rotate or twist along the
curve's length), whereas Surfaces have normal vectors and tangent planes that will be
consistent in their orientation.
1. Surface
2. U Isocurve
3. V Isocurve
4. UV Coordinate
5. Perpendicular Plane
6. Normal Vector
Surface Domain: A surface domain is defned as the range of (U,V) parameters that evaluate
into a three dimensional point on that surface. The domain in each dimension (U or V) is
usually described as two numbers (U Min to U Max) and (V Min to V Max).
Although the shape of the Surface by not look "rectangular" and it locally may have a tighter or
looser set of isocurves, the "space" defned by its domain is always two dimensional. In
Dynamo, Surfaces are always understood to have a domain defned by a minimum of 0.0 and
maximum of 1.0 in both U and V directions. Planar or trimmed Surfaces may have different
domains.
Isocurve (or Isoparametric Curve): A curve defned by a constant U or V value on the surface
and a domain of values for the corresponding other U or V direction.
Normal Vector: A Vector defning the direction of "up" relative to the Perpendicular Plane.
NURBS Surfaces
NURBS Surfaces are very similar to NURBS curves. You can think of NURBS Surfaces as a
grid of NURBS Curves that go in two directions. The shape of a NURBS Surface is defned by
a number of control points and the degree of that surface in the U and V directions. The same
algorithms are used to calculate shape, normals, tangents, curvatures and other properties by
way of control points, weights and degree.
In the case of NURBS surfaces, there are two directions implied by the geometry, because
NURBS surfaces are, regardless of the shape we see, rectangular grids of control points. And
even though these directions are often arbitrary relative to the world coordinate system, we will
use them frequently to analyze our models or generate other geometry based on the Surface.
While "Topology" generally describes a concept around how parts are connected and/or
related Topology in Dynamo is also a type of Geometry. Specifcally it is a parent category
for Surfaces, Polysurfaces, and Solids.
Sometimes called patches, joining Surfaces in this manner allows us to make more complex
shapes as well as defne detail across the seam. Conveniently we can apply a fllet or chamfer
operation to the edges of a Polysurface.
Let's import and evaluate a Surface at a Parameter in Dynamo to see what kind of information
we can extract.
1. Surface.PointAtParameter returns the Point at a given UV Coordinate
2. Surface.NormalAtParameter returns the Normal Vector at a given UV Coordinate
3. Surface.GetIsoline returns the Isoparametric Curve at a U or V Coordinate - note the
isoDirection input.
Download the example fles that accompanies this image (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix.
Solids
If we want to construct more complex models that cannot be created from a single surface or if
we want to defne an explicit volume, we must now venture into the realm of Solids (and
Polysurfaces). Even a simple cube is complex enough to need six surfaces, one per face.
Solids give access to two key concepts that Surfaces do not - a more refned topological
description (faces, edges, vertices) and Boolean operations.
What's a Solid?
Solids consist of one or more Surfaces that contain volume by way of a closed boundary that
defnes "in" or "out." Regardless of how many of these Surfaces there are, they must form a
"watertight" volume to be considered a Solid. Solids can be created by joining Surfaces or
Polysurfaces together or by using operations such as loft, sweep, and revolve. Sphere, Cube,
Cone and Cylinder primitives are also Solids. A Cube with at least one face removed counts as
a Polysurface, which has some similar properties, but it is not a Solid.
Topology
Solids are made up of three types of elements: Vertices, Edges, and Faces. Faces are the
surfaces that make up the Solid. Edges are the Curves that defne the connection between
adjacent faces, and vertices are the start and end points of those Curves. These elements can
be queried using the Topology nodes.
1. Faces
2. Edges
3. Vertices
Operations
Solids can be modifed by flleting or chamfering their edges to eliminate sharp corners and
angles. The chamfer operation creates a ruled surface between two faces, while a fllet blends
between faces to maintain tangency.
1. Solid Cube
2. Chamfered Cube
3. Filleted Cube
Boolean Operations
Solid Boolean operations are methods for combining two or more Solids. A single Boolean
operation actually means performing four operations:
This makes Solid Booleans a powerful time-saving process. There are three Solid Boolean
operations that distinguish which parts of the geometry are kept.
1. Union: Remove the overlapping portions of the Solids and join them into a single
Solid.
2. Difference: Subtract one Solid from another. The Solid to be subtracted is referred to
as a tool. Note that you could switch which Solid is the tool to keep the inverse
volume.
3. Intersection: Keep only the intersecting volume of the two Solids.
In addition to these three operations, Dynamo has Solid.DifferenceAll and Solid.UnionAll nodes
for performing difference and union operations with multiple Solids.
Download the example fles that accompany this image (Right click and "Save Link As...").
A full list of example fles can be found in the Appendix. Geometry for Computational
Design - Solids.dyn
Freezing
Boolean operations are complex and can be slow to calculate. Use Freeze functionality to
suspend the execution of selected nodes and affected downstream nodes.
Use the right-click contextual menu to Freeze the Solid Union operation
The selected node and all downstream nodes will preview in a light grey ghosted mode,
and affected wires will be displayed as dashed lines. The affected geometry preview will
also be ghosted. You can now change values upstream without calculating the boolean
union.
To unfreeze the nodes, right-click and uncheck Freeze.
All affected nodes and associated geometry previews will update and revert to the
standard preview mode.
Meshes
In the feld of computational modeling, Meshes are one of the most pervasive forms of
representing 3D geometry. Mesh geometry can be a light-weight and fexible alternative to
working with NURBS, and Meshes are used in everything from rendering and visualizations to
digital fabrication and 3D printing.
What's a Mesh?
A Mesh is a collection of quadrilaterals and triangles that represents a surface or solid
geometry. Like Solids, the structure of a Mesh object includes vertices, edges, and faces.
There are additional properties that make Meshes unique as well, such as normals.
1. Mesh vertices
2. Mesh edges *Edges with only one adjoining face are called "Naked." All other edges
are "Clothed"
3. Mesh faces
Mesh Elements
Dynamo defnes Meshes using a Face-Vertex data structure. At its most basic level, this
structure is simply a collection of points which are grouped into polygons. The points of a Mesh
are called vertices, while the surface-like polygons are called faces. To create a Mesh we need
a list of vertices and a system of grouping those vertices into faces called an index group.
1. List of vertices
2. List of index groups to defne faces
The vertices of a Mesh are simply a list of points. The index of the vertices is very important
when constructing a Mesh, or getting information about the structure of a Mesh. For each
vertex, there is also a corresponding vertex normal (vector) which describes the average
direction of the attached faces and helps us understand the "in" and "out" orientation of the
Mesh.
1. Vertices
2. Vertex Normals
Faces
A face is an ordered list of three or four vertices. The “surface” representation of a Mesh face is
therefore implied according to the position of the vertices being indexed. We already have the
list of vertices that make up the Mesh, so instead of providing individual points to defne a face,
we simply use the index of the vertices. This also allows us to use the same vertex in more
than one face.
Parameterization
In a previous chapter, we saw that NURBS surfaces are defned by a series of NURBS curves
going in two directions. These directions are labeled U and V , and allow a NURBs surface
to be parameterized according to a two-dimensional surface domain. The curves themselves
are stored as equations in the computer, allowing the resulting surfaces to be calculated to an
arbitrarily small degree of precision. It can be diffcult, however, to combine multiple NURBS
surfaces together. Joining two NURBS surfaces will result in a polysurface, where different
sections of the geometry will have different UV parameters and curve defnitions.
1. Surface
2. Isoparametric (Isoparm) Curve
3. Surface Control Point
4. Surface Control Polygon
5. Isoparametric Point
6. Surface Frame
7. Mesh
8. Naked Edge
9. Mesh Network
10. Mesh Edges
11. Vertex Normal
12. Mesh Face / Mesh Face Normal
Meshes, on the other hand, are comprised of a discrete number of exactly defned vertices and
faces. The network of vertices generally cannot be defned by simple UV coordinates, and
because the faces are discrete the amount of precision is built into the Mesh and can only be
changed by refning the Mesh and adding more faces. The lack of mathematical descriptions
allows Meshes to more fexibly handle complex geometry within a single Mesh.
One analogy that can be helpful is to compare a vector image (composed of lines and curves)
with a raster image (composed of individual pixels). If you zoom into a vector image, the curves
remain crisp and clear, while zooming into a raster image results in seeing individual pixels
become larger. In this analogy, NURBS surfaces can be compared to a vector image because
there is a smooth mathematical relationship, while a Mesh behaves similarly to a raster image
with a set resolution.
Mesh Toolkit
Dynamo's mesh capabilities can be extended by installing the Mesh Toolkit package. The
Dynamo Mesh Toolkit provides tools to import Meshes from external fle formats, create a
Mesh from Dynamo geometry objects, and manually build Meshes by their vertices and
indices. The library also provides tools to modify Meshes, repair Meshes, or extract horizontal
slices for use in fabrication.
There are several ways to import geometry into Dynamo. We've demonstrated importing
meshes using Mesh Toolkit in the previous section - we can also import Solid models from
.SAT fles. With these processes, we can develop geometry in another platform, load it into
Dynamo, and apply parametric operations through visual programming.
Another method for importing geometry uses a process called ATF Translation . In this case,
we can import not just geometry, but a fle's structure. For example, we can choose which
layers of a .DWG to import rather than importing the entire model. We'll demonstrate this below
in more detail.
As shown in the above image, all types of geometry in the DWG fle - surfaces, meshes,
curves and lines - are imported into Dynamo.
Object Filter
To specify which geometries are imported from the DWG fle, additional ObjectFilter nodes can
be added to the defnition. The ObjectFilter node is compatible with either a FileLoader or a list
of ImportedObject, and outputs an ImportedObject list.
The following images show the conditional statements within each ObjectFilter node. Any
ImportedObject that satisfes any of the listed conditions will pass through the flter. Filtering
can be based on layer label (i.e. layer name), geometry type, diffuse color, etc., and can be
used in conjunction with other flters to refne the selection.
1. Replace FileLoader.GetImportedObjects with ObjectFilter to search for specifc
conditions in the DWG fle. – in this case only surface geometry will be imported,
removing all curve and line geometry visible in the previous image.
2. Connect Filter to ImportedObject.ConvertToGeometries to import the fltered
geometry.
By adding two flters with different conditional statements, we can divide the list of geometry
into multiple streams:
1. Replace FileLoader.GetImportedObjects with two ObjectFilter modules of different
conditional statements. This will separate the geometry from one fle into two different
streams.
2. Connect Filter to ImportedObject.ConvertToGeometries to import the fltered
geometry.
3. Connect ImportedObject.ConvertToGeometries to Display.ByGeometryColor to
visualize each stream in a different color.
Designing with Lists
Lists are the way we organize data. On your computer's operating system, you have fles and
folders. In Dynamo, we can regard these as items and lists, respectively. Like your operating
system, there are many ways to create, modify, and query data. In this chapter, we'll break
down how lists are managed in Dynamo.
What's a List?
A list is a collection of elements, or items. Take a bunch of bananas, for example. Each
banana is an item within the list (or bunch). It's easier to pick up a bunch of bananas rather
than each banana individually, and the same holds for grouping elements by parametric
relationships in a data structure.
When we buy groceries, we put all of the purchased items into a bag. This bag is also a list. If
we're making banana bread, we need 3 bunches of bananas (we're making a lot of banana
bread). The bag represents a list of banana bunches and each bunch represents a list of
bananas. The bag is a list of lists (two-dimensional) and the banana is a list (one-dimensional).
In Dynamo, list data is ordered, and the frst item in each list has an index "0". Below, we'll
discuss how lists are defned in Dynamo and how multiple lists relate to one another.
Zero-Based Indices
One thing that might seem odd at frst is that the frst index of a list
For example, if you were to count the number of fngers we have on our right
Note that we still have 5 items in the list; it’s just that the list is using a zero-based
counting
system. And the items being stored in the list don’t just have to be
Often times the easiest way to take a look at the type of data stored in a list
is to connect a
watch node to another node's output. By default, the watch node automatically shows all
indices to the left side of the list and displays the data items on the right.
These indices are a crucial element when working with lists.
1. The points input for PolyCurve.ByPoints is looking for "Point[]". This represents a list
of points.
2. The output for PolyCurve.ByPoints is a single PolyCurve created from a list of fve
points.
3. The centerPoint input for Circle.ByCenterPointRadius asks for "Point".
4. The output for Circle.ByCenterPointRadius is a list of fve circles, whose centers
correspond to the original list of points.
The input data for PolyCurve.ByPoints and Circle.ByCenterPointRadius are the same, however
the Polycurve node gives us one polycurve while the Circle node gives us 5 circles with
centers at each point. Intuitively this makes sense: the polycurve is drawn as a curve
connecting the 5 points, while the circles create a different circle at each point. So what's
happening with the data?
Hovering over the points input for Polycurve.ByPoints, we see that the input is looking for
"Point[]". Notice the brackets at the end. This represents a list of points, and to create a
polycurve, the input needs to be a list for each polycurve. This node will therefore condense
each list into one polycurve.
On the other hand, the centerPoint input for Circle.ByCenterPointRadius asks for "Point". This
node looks for one point, as an item, to defne the center point of the circle. This is why we get
fve circles from the input data. Recognizing these difference with inputs in Dynamo helps to
better understand how the nodes are operating when managing data.
Lacing
Data matching is a problem without a clean solution. It occurs when a node has access to
differently sized inputs. Changing the data matching algorithm can lead to vastly different
results.
As you can see there are different ways in which we can draw lines between these sets of
points. Lacing options are found by right-clicking the center of a node and choosing the
"Lacing" menu.
Base File
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Lacing.dyn. A full list of example fles can be found in the Appendix.
To demonstrate the lacing operations below, we'll use this base fle to defne shortest list,
longest list, and cross product.
1. We'll change the lacing on Point.ByCoordinates, but won't change anything else
about the graph above.
Shortest List
The simplest way is to connect the inputs one-on-one until one of the streams runs dry. This is
called the “Shortest List” algorithm. This is the default behavior for Dynamo nodes:
By changing the lacing to shortest list, we get a basic diagonal line composed of fve
points. Five points is the length of the lesser list, so the shortest list lacing stops after it
reaches the end of one list.
Longest List
The “Longest List” algorithm keeps connecting inputs, reusing elements, until all streams run
dry:
By changing the lacing to longest list, we get a diagonal line which extends vertically. By
the same method as the concept diagram, the last item in the list of 5 items will be
repeated to reach the length of the longer list.
Cross Product
By changing the lacing to Cross Product, we get every combination between each list,
giving us a 5x10 grid of points. This is an equivalent data structure to the cross product as
shown in the concept diagram above, except our data is now a list of lists. By connecting
a polycurve, we can see that each list is defned by its X-Value, giving us a row of vertical
lines.
Working with Lists
Now that we've established what a list is, let's talk about operations we can perform on it.
Imagine a list as a deck of playing cards. A deck is the list and each playing card represents an
item.
What queries can we make from the list? This accesses existing properties.
What actions can we perform on the list? This changes the list based on a given operation.
We can shuffe the deck.
We can sort the deck by value.
We can sort the deck by suit.
We can split the deck.
We can partition the deck by dealing out individual hands.
We can select a specifc card in the deck.
All of the operations listed above have analogous Dynamo nodes for working with lists of
generic data. The lessons below will demonstrate some of the fundamental operations we can
perform on lists.
List Operations
The image below is the base graph we will be using to demonstrate basic list operations. We'll
explore how to manage data within a list and demonstrate the visual results.
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): List-Operations.dyn. A full list of example fles can be found in the Appendix.
1. Begin with a code block with a value of 500;
2. Plug into the x input of a Point.ByCoordinates node.
3. Plug the node from the previous step into the origin input of a Plane.ByOriginNormal
node.
4. Using a Circle.ByPlaneRadius node, plug the node from the previous step into the
plane input.
5. Using code block, designate a value of 50; for the radius. This is the frst circle we'll
create.
6. With a Geometry.Translate node, move the circle up 100 units in the Z direction.
7. With a code block node, defne a range of ten numbers between 0 and 1 with this line
of code: 0..1..#10;
8. Plug the code block from the previous step into the param input of two
Curve.PointAtParameter nodes. Plug Circle.ByPlaneRadius into the curve input of the
top node, and Geometry.Translate into the curve input of the node beneath it.
9. Using a Line.ByStartPointEndPoint, connect the two Curve.PointAtParameter nodes.
1. A Watch3D node shows the results of the Line.ByStartPointEndPoint. We are
drawing lines between two circles to represent basic list operations and will use this
base Dynamo graph to walk through the list actions below.
List.Count
The List.Count node is straightforward: it counts the number of values in a list and returns
that number. This node gets more nuanced as we work with lists of lists, but we'll
demonstrate that in the coming sections.
Exercise - List.Count
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): List-Count.dyn. A full list of example fles can be found in the Appendix.
List.GetItemAtIndex
List.GetItemAtIndex is a fundamental way to query an item in the list. In the image above,
we are using an index of "2" to query the point labeled "C".
Exercise - List.GetItemAtIndex
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): List-GetItemAtIndex.dyn. A full list of example fles can be found in the Appendix.
1. Using the List.GetItemAtIndex node, we are selecting index "0", or the frst item in the
list of lines.
2. The Watch3D node reveals that we've selected one line. Note: to get the image
above, be sure to disable the preview of Line.ByStartPointEndPoint.
List.Reverse
Exercise - List.Reverse
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): List-Reverse.dyn. A full list of example fles can be found in the Appendix.
1. To properly visualize the reversed list of lines, create more lines by changing the
code block to 0..1..#100;
2. Insert a List.Reverse node in between Curve.PointAtParameter and
Line.ByStartPointEndPoint for one of the list of points.
3. The Watch3D nodes show two different results. The frst one shows the result without
a reversed list. The lines connect vertically to neighboring points. The reversed list,
however, will connect all of the points to the opposing order in the other list.
List.ShiftIndices
List.ShiftIndices is a good tool for creating twists or helical patterns, or any other similar
data manipulation. This node shifts the items in a list a given number of indices.
Exercise - List.ShiftIndices
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): List-ShiftIndices.dyn. A full list of example fles can be found in the Appendix.
1. In the same process as the reverse list, insert a List.ShiftIndices into the
Curve.PointAtParameter and Line.ByStartPointEndPoint.
2. Using a code block, designated a value of "1" to shift the list one index.
3. Notice that the change is subtle, but all of the lines in the lower Watch3D node have
shifted one index when connecting to the other set of points.
1. By changing to code block to a larger value, "30" for example, we notice a signifcant
difference in the diagonal lines. The shift is working like a camera's iris in this case,
creating a twist in the original cylindrical form.
List.FilterByBooleanMask
List.FilterByBooleanMask will remove certain items based on a list of booleans, or values
reading "true" or "false".
Exercise - List.FilterByBooleanMask
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): List-FilterByBooleanMask.dyn. A full list of example fles can be found in the
Appendix.
In order to create a list of values reading "true" or "false", we need to a little more work...
Lists of Lists
Let's add one more tier to the hierarchy. If we take the deck of cards from the original example
and create a box which contains multiple decks, the box now represents a list of decks, and
each deck represents a list of cards. This is a list of lists. For the analogy in this section, the
red box below contains a list of coin rolls, and each roll contains a list of pennies.
Photo by Dori.
What queries can we make from the list of lists? This accesses existing properties.
Again, Dynamo has an analagous node for each one of the operations above. Since we're
working with abstract data and not physical objects, we need a set of rules to govern how we
move up and down the data hierarchy.
When dealing with lists of lists, the data is layered and complex, but this provides an
opportunity to do some awesome parametric operations. Let's break down the fundamentals
and discuss a few more operations in the lessons below.
Top-Down Hierarchy
The fundamental concept to learn from this section: Dynamo treats lists as objects in and of
themselves. This top-down hierarchy is developed with object-oriented programming in mind.
Rather than selecting sub-elements with a command like List.GetItemAtIndex, Dynamo will
select that index of the main list in the data structure. And that item can be another list. Let's
break it down with an example image:
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Top-Down-Hierarchy.dyn . A full list of example fles can be found in the Appendix.
1. With code block, we've defned two ranges:```
0..2;
0..3;
```
2. These ranges are connected to a Point.ByCoordinates node with lacing set to "Cross
Product". This creates a grid of points, and also returns a list of lists as an output.
3. Notice that the Watch node gives 3 lists with 4 items in each list.
4. When using List.GetItemAtIndex, with an index of 0, Dynamo selects the frst list and
all of its contents. Other programs may select the frst item of every list in the data
structure, but Dynamo employs a top-down hierarchy when dealing with data.
Exercise - Flatten
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Flatten.dyn. A full list of example fles can be found in the Appendix.
-250..-150..#4;
```
2. Plugging the code block into the x and y input of a Point.ByCoordinates node, we set
the lacing to "Cross Product" to get a grid of points.
3. The Watch node shows that we have a list of lists.
4. A PolyCurve.ByPoints node will reference each list and create a respective polycurve.
Notice in the Dynamo preview that we have four polycurve representing each row in
the grid.
1. By inserting a fatten before the polycurve node, we've created one single list for all of
the points. The polycurve node references a list to create one curve, and since all of
the points are on one list, we get one zig-zag polycurve which runs throughout the
entire list of points.
There are also options for fattening isolated tiers of data. Using the List.Flatten node, you can
defne a set number of data tiers to fatten from the top of the hierarchy. This is a really helpful
tool if you're struggling with complex data structures which are not necessarily relevant to your
workfow. And another option is to use the fatten node as a function in List.Map. We'll discuss
List.Map more below.
Chop
When parametric modeling, there are also times where you'll want to add more data structure
to an existing list. There are many nodes available for this as well, and chop is the most basic
version. With chop, we can partition a list into sublists with a set number of items.
Exercise - List.Chop
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Chop.dyn. A full list of example fles can be found in the Appendix.
The chop command divides lists based on a given list length. In some ways, chop is the
opposite of fatten: rather than removing data structure, it adds new tiers to it. This is a helpful
tool for geometric operations like the example below.
Exercise - List.Map
Note: This exercise was created with a previous version of Dynamo. Much of the List.Map
functionality has been resolved with the addition of the List@Level feature. For more
information, see List@Level below.
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Map.dyn. A full list of example fles can be found in the Appendix.
As a quick introduction, let's review the List.Count node from a previous section.
The List.Count node counts all of the items in a list. We'll use this to demonstrate how
List.Map works.
1. Insert two lines of code into the code block:
-50..50..#Nx;
-50..50..#Ny;
After typing in this code, the code block will create two inputs for Nx and Ny.
2. With two integer sliders, defne the Nx and Ny values by connecting them to the code
block.
3. Connect each line of the code block into the respective X and Y inputs of a
Point.ByCoordinates node. Right click the node, select "Lacing", and choose "Cross
Product". This creates a grid of points. Because we defned the range from -50 to 50,
we are spanning the default Dynamo grid.
4. A Watch node reveals the points created. Notice the data structure. We've created a
list of lists. Each list represents a row of points of the grid.
1. Attach a List.Count node to the output of the watch node from the previous step.
2. Connect a Watch node to the List.Count output.
Notice that the List.Count node gives a value of 5. This is equal to the "Nx" variable as defned
in the code block. Why is this?
First, the Point.ByCoordinates node uses the "x" input as the primary input for creating
lists. When Nx is 5 and Ny is 3, we get a list of 5 lists, each with 3 items.
Since Dynamo treats lists as objects in and of themselves, a List.Count node is applied to
the main list in the hierarchy. The result is a value of 5, or, the number of lists in the main
list.
1. By using a List.Map node, we take a step down in the hierarchy and perform a
"function" at this level.
2. Notice that the List.Count node has no input. It is being used as a function, so the
List.Count node will be applied to every individual list one step down in the hierarchy.
The blank input of List.Count corresponds to the list input of List.Map.
3. The results of List.Count now gives a list of 5 items, each with a value of 3. This
represents the length of each sublist.
Exercise - List.Combine
Note: This exercise was created with a previous version of Dynamo. Much of the List.Combine
functionality has been resolved with the addition of the List@Level feature. For more
information, see List@Level below.
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Combine.dyn. A full list of example fles can be found in the Appendix.
In this exercise, we'll use a similar logic to List.Map, but with multiple elements. In this case, we
want to divide a list of curves by a unique number of points.
1. Using the code block, defne a range using the syntax: ```..20..#4;
and a value of 20;
``` below that line.
2. Connect the code block to two Point.ByCoordinates nodes.
3. Create a Line.ByStartPointEndPoint from the Point.ByCoordinates nodes.
4. The Watch node shows four lines.
1. Below the graph for line creation, we want to use _code block _to create four distinct
ranges to divide the lines uniquely. We do this with the following lines of code:
0..1..#3;
0..1..#4;
0..1..#5;
0..1..#6;
2. With a List.Create node, we merge the four lines from the code block into one list.
3. The Watch node reveals a list of lists.
1. Curve.PointAtParameter will not work by connecting the lines directly into the
parameter values. We need to step one level down on the hierarchy. For this, we'll
use List.Combine.
By using List.Combine, we can successfully divide each line by the given ranges. This
gets a little tricky, so we'll break it down in-depth.
1. First, add a Curve.PointAtParameter node to the canvas. This will be the "function"
_or "combinator" that we apply to _List.Combine node. More on that in a second.
2. Add a List.Combine node to the canvas. Hit the "+" or "-" to add or subtract inputs. In
this case, we'll use the default two inputs on the node.
3. We want to plug the Curve.PointAtParameter node into the "comb" input of
List.Combine. And one more important node: be sure to right-click the "param" _input
of _Curve.PointAtParameter and uncheck "use default value". Default values in
Dynamo inputs have to be removed when running a node as a function. In other
words, we should consider default values as having additional nodes wired to them.
Because of this, we need to remove the default values in this case.
4. We know we have two inputs, the lines and the parameters to create points. But how
do we connect them to the List.Combine inputs and in what order?
5. The empty inputs of Curve.PointAtParameter, from top-to-bottom need to be flled in
the combinator in the same order. So, the lines are plugged into list1 of List.Combine.
6. Following suit, the parameter values are plugged into the list2 input of List.Combine.
7. The Watch node and the Dynamo preview shows us that we have 4 lines, each
divided based on the code block ranges.
List@Level
Preferred to List.Map, the List@Level feature allows you to directly select which level of list you
want to work with right at the input port of the node. This feature can be applied to any
incoming input of a node and will allow you access the levels of your lists quicker and easier
than other methods. Just tell the node what level of the list you want to use as the input and let
the node do the rest.
List@Level Exercise
In this exercise, we will use the List@Level feature to isolate a specifc level of data.
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): List@Level. A full list of example fles can be found in the Appendix.
1. To use the List@Level function, click '>'. Inside this menu, you will see two
checkboxes.
2. Use Levels - This enables the List@Level functionality. After clicking on this option,
you will be able to click through and select the input list levels you want the node to
use. With this menu, you can quickly try out different level options by clicking up or
down.
3. Keep list structure – If enabled, you will have the option to keep that input’s level
structure. Sometimes, you may have purposefully organized your data into sublists.
By checking this option, you can keep your list organization intact and not lose any
information.
With our simple 3D grid, we can access and visualize the list structure by toggling through the
List Levels. Each List Level and index combination will return a different set of points from our
original 3D set.
1. “@L2” in DesignScript allows us to select only the List at Level 2.
2. The List at Level 2 with the index 0 includes only the frst set of Y points, returning
only the XZ grid.
3. If we change the Level flter to “L1”, we will be able to see everything in the frst List
Level. The List at Level 1 with the index 0 includes all of our 3D points in a fat list.
4. If we try the same for “L3” we will see only the third List Level points. The List at Level
3 with the index 0 includes only the frst set of Z points, returning only an XY grid.
5. If we try the same for “L4” we will see only the third List Level points. The List at Level
4 with the index 0 includes only the frst set of X points, returning only an YZ grid.
Although this particular example can also be created with List.Map, List@Level greatly
simplifes the interaction, making it easy to access the node data. Take a look below at a
comparison between a List.Map and List@Level methods:
1. Although both methods will give us access to the same points, the List@Level
method allows us to easily toggle between layers of data within a single node.
2. To access a point grid with List.Map, we will need a List.GetItemAtIndex node
alongside the List.Map. For every list level that we are stepping down, we will need to
use an additional List.Map node. Depending on the complexity of your lists, this could
require you to add a signifcant amount of List.Map Nodes to your graph to access the
right level of information.
3. In this example, a List.GetItemAtIndex node with a List.Map node reurns the same
set of points with the same list structure as the List.GetItemAtIndex with '@L3'
selected.
Transpose
Transpose is a fundamental function when dealing with lists of lists. Just as in spreadsheet
programs, a transpose fips the columns and rows of a data structure. We'll demonstrate this
with a basic matrix below, and in the following section, we'll demonstrate how a transpose can
be use to create geometric relationships.
Exercise - List.Transpose
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."): Transpose.dyn. A full list of example fles can be found in the Appendix.
Let's delete the List.Count nodes from the previous exercise and move on to some
geometry to see how the data structured.
This exercise uses some of the logic established in the previous one to edit a surface. Our goal
here is intuitive, but the data structure navigation will be more involved. We want to articulate a
surface by moving a control point.
1. Begin with the string of nodes above. We are creating a basic surface which spans
the default Dynamo grid.
2. Using code block, insert these two lines of code and connect to the u and v inputs of
Surface.PointAtParameter, respectively:
-50..50..#3;
-50..50..#5;
1. To confrm that this is the correct point, we can also click through the watch node
items to confrm that we're targeting the correct one.
2. Using code block, we'll write a basic line of code for querying a list of lists:
points[1][2];
3. Using Geometry.Translate , we'll move the selected point up in the Z direction by 20
units.
1. Let's also select the middle row of points with a List.GetItemAtIndex node. Note:
Similar to a previous step, we can also query the list with code block, using a line of
points[1];
So far we've successfully queried the center point and moved it upward. Now we want
need to insert this moved point back into the original data structure.
1. First, we want to replace the item of the list we isolated in a previous step.
2. Using List.ReplaceItemAtIndex, we'll replace the middle item by using and index of
"2", with the replacement item connected to the moved point (Geometry.Translate ).
3. The output shows that we've input the moved point into the middle item of the list.
Now that we've modifed the list, we need to insert this list back into the original data
structure: the list of lists.
1. Following the same logic, use List.ReplaceItemAtIndex to replace the middle list with
the our modifed list.
2. Notice that the code blocks defning the index for these two nodes are 1 and 2, which
matches the original query from the code block (points[1][2]).
3. By selecting the list at index 1, we see the data structure highlighted in the Dynamo
preview. We successfully merged the moved point into the original data structure.
There are many ways to make a surface from this set of points. In this case, we're going
to create a surface by lofting curves together.
1. Create a NurbsCurve.ByPoints node and connect the new data structure to create
three nurbs curves.
1. Connect a Surface.ByLoft to the output from NurbsCurve.ByPoints. We now have a
modifed surface. We can change the original Z value of Geometry. Translate and
watch the geometry update!
n-Dimensional Lists
Further down the rabbit-hole, let's add even more tiers to hierarchy. Data structure can expand
far beyond a two-dimensional list of lists. Since lists are items in and of themselves in Dynamo,
we can create data with as many dimensions as possible.
The analogy we'll work with here are Russian Nesting Dolls. Each list can be regarded as one
container holding multiple items. Each list has its own properties and is also regarded as its
own object.
A set of Russian Nesting Dolls (Photo by Zeta) is an analogy for n-Dimensional lists. Each
layer represents a list, and each list contains items within it. In Dynamo's case, each
container can have multiple containers inside (representing the items of each list).
n-Dimensional lists are diffcult to explain visually, but we've set up a few exercises in this
chapter which focus on working with lists which venture beyond two dimensions.
Mapping is arguably the most complex part of data management in Dynamo, and is especially
relevant when working with complex hierarchies of lists. With the series of exercises below,
we'll demonstrate when to use mapping and combinations as data becomes multi-dimensional.
Preliminary introductions to List.Map and List.Combine can be found in the previous section. In
the last exercise below, we'll use these nodes on a complex data structure.
1. n-Dimensional-Lists.dyn
2.n-Dimensional-Lists.sat
This exercise is the frst in a series of three which focuses on articulating imported geometry.
Each part in this series of exercises will increase in the complexity of data structure.
1. Let's begin with the .sat fle in the exercise fle folder. We can grab this fle using the
File Path node.
2. With Geometry.ImportFromSAT , the geometry is imported into our Dynamo preview
as two surfaces.
For this exercise, we want to keep it simple and work with one of the surfaces.
1. Let's select the index of 1 to grab the upper surface. We do this with
List.GetItemAtIndex node.
0..1..#10;
0..1..#5;
2. With the Surface.PointAtParameter, connect the two code block values to u and v.
Change the lacing of this node to "Cross Product".
3. The output reveals the data structure, which is also visible in the Dynamo preview.
0..1..#10;
0..1..#5;
2. Connect these outputs to two Surface.PointAtParameter nodes, each with lacing set
to "Cross Product". One of these nodes is connected to the original surface, while the
other is connected to the offset surface.
1. As in the previous exercise, connect the outputs to two NurbsCurve.ByPoints nodes.
2. Our Dynamo preview shows two curves, corresponding to two surfaces.
1. By using List.Create, we can combine the two sets of curves into one list of lists.
2. Notice from the output, we have two lists with ten items each, representing each
connect set of nurbs curves.
3. By performing a Surface.ByLoft, we can visually make sense of this data structure.
The node lofts all of the curves in each sublist.
1. By using List.Transpose, remember, we are fipping all of the columns and rows. This
node will transfer two lists of ten curves into ten lists of two curves. We now have
each nurbs curve related to the neighboring curve on the other surface.
2. Using Surface.ByLoft, we arrive at a ribbed structure.
1. An alternative to List.Transpose uses List.Combine. This will operate a "combinator"
on each sublist.
2. In this case, we're using List.Create as the "combinator", which will create a list of
each item in the sublists.
3. Using the Surface.ByLoft node, we get the same surfaces as in the previous step.
Transpose is easier to use in this case, but when the data structure becomes even
more complex, List.Combine is more reliable.
1. Stepping back a few steps, if we want to switch the orientation of the curves in the
ribbed structure, we want to use a List.Transpose before connect to
NurbsCurve.ByPoints. This will fip the columns and rows, giving us 5 horizontal ribs.
Exercise - 3D Lists
Now, we're going to go even one step further. In this exercise, we'll work with both imported
surfaces, creating a complex data hierarchy. Still, our aim is to complete the same operation
with the same underlying logic.
1. Begin with the imported fle from previous exercise.
1. As in the previous exercise, use the Surface.Offset node to offset by a value of 10.
2. Notice from the output, that we've created two surfaces with the offset node.
1. In the same manner as the previous exercise, defne a code block with these two
lines of code:
0..1..#20;
0..1..#10;
2. Connect these outputs to two Surface.PointAtParameter nodes, each with lacing set
to "Cross Product". One of these nodes is connected to the original surfaces, while
the other is connected to the offset surfaces.
1. As in the previous exercise, connect the outputs to two NurbsCurve.ByPoints nodes.
2. Looking at the output of the NurbsCurve.ByPoints, notice that this is a list of two lists,
which is more complex than the previous exercise. The data is categorized by the
underlying surface, so we've added another tier to the data structured.
3. Notice that things become more complex in the Surface.PointAtParameter node. In
this case we have a list of lists of lists.
1. Using the List.Create node, we merge the nurbs curves into one data structure,
creating a list of lists of lists.
2. By connecting a Surface.ByLoft node, we get a version of the original surfaces, as
they each remain in their own list as created from the original data structure.
1. List.Combine will work better for us here. We want to use List.Map and List.Combine
nodes when we get to more complex data structures.
2. Using List.Create as the "combinator", we create a data structure that will work better
for us.
1. The data structure still needs to be transposed at one step down on the hierarchy. To
do this we'll use List.Map. This is working like List.Combine, except with one input list,
rather than two or more.
2. The function we'll apply to List.Map is List.Transpose, which will fip the columns and
rows of the sublists within our main list.
1. Finally, we can loft the nurbs curves together with a proper data hierarchy, giving us a
ribbed structure.
1. It'll be nice to add a surface backing two this structure, so we'll use
List.GetItemAtIndex to select the back surface from the lofted surfaces from the
previous steps.
Not the most comfortable rocking chair ever, but it's got a lot of data going on.
Last step, let's reverse the direction of the striated members. As we used transpose in the
previous exercise, we'll do something similar here.
1. Since we have one more tier to the hierarchy, so we need to use List.Map with a
List.Tranpose function to change the direction of our nurbs curves.
1. We may want to increase the number of treads, so we can change the code block to
0..1..#20;
0..1..#10;
The frst version of the rocking chair was sleek, so our second model offers an off-road,
sport-utility version of recumbency.
Code Blocks and DesignScript
The code block is a unique feature in Dynamo that dynamically links a visual programming
environment with a text-based one. The code-block has access to all of the Dynamo nodes
and can defne an entire graph in one node. Read this chapter closely, as the code block is a
fundamental building block of Dynamo.
What's a Code Block?
Code blocks are a window deep into DesignScript, the programming language at the heart of
Dynamo. Built from scratch to support exploratory design workfows, DesignScript is a
readable and concise language that offers both immediate feedback to small bits of code and
also scales to large and complex interactions. DesignScript also forms the backbone of the
engine that drives most aspects of Dynamo “under the hood”. Because nearly all of the
functionality found in Dynamo nodes and interactions have a one-to-one relationship with the
scripting language, there are unique opportunities to move between node-based interactions
and scripting in a fuid way.
For beginners, nodes can be automatically converted to text syntax to aid in learning
DesignScript or simply to reduce the size of larger sections of graphs. This is done using a
process called "Node to Code", which is outlined in more detail in the DesignScript Syntax
section. More experienced users can use Code Blocks to create customized mashups of
existing functionality and user authored relationships using many standard coding paradigms.
In between the beginner and advanced user, there are a huge number of shortcuts and code
snippets that will accelerate your designs. While the term 'code block' may be a little
intimidating to non-programmers, it is both easy to use and robust. A beginner can use the
code block effciently with minimal coding, and an advanced user can defne scripted
defnitions to be recalled elsewhere in a Dynamo defnition.
With code blocks, a user has the fexibility to decide how to specify inputs. Here are several
different ways to make a basic point with coordinates (10, 5, 0):
As you learn more of the available functions in the library, you might even fnd that typing
“Point.ByCoordinates” is faster than searching in the library and fnding the proper node. When
you type in "Point." for example, Dynamo will display a list of possible functions to apply to a
Point. This makes the scripting more intuitive and will help with learning how to apply functions
in Dynamo.
In the image below, you can see the "old school" way of doing things is a little long-winded: the
user searches for the intended node in the interface, adds the node to the canvas, and then
inputs the data. With code block, the user can double-click on the canvas to pull up the node,
and type in the correct data type with basic syntax.
The number, string, and formula nodes are three examples of Dynamo nodes which are
arguably obsolete in comparison to the code block.
DesignScript Syntax
You may have noticed a common theme in the names of nodes in Dynamo: each node uses a
"." syntax without spaces. This is because the text at the top of each node respresents the
actual syntax for scripting, and the "." (or dot notation) separates an element from the possible
methods we can call. This creates an easy translation from visual scripting to text-based
scripting.
As a general analogy for the dot notation, how can we deal with a parametric apple in
Dynamo? Below are a few methods we'll run on the apple before deciding to eat it. (Note:
these are not actual Dynamo methods):
I don't know about you, but judging by the outputs in the table above, this looks like one tasty
apple. I think I'll Apple.eat() it.
1. By using Point.ByCoordinates in the code block, we are specifying the inputs in the
same order as the out-of-the-box node (X,Y).
Calling Nodes
You can call any regular node in the library through a Code Block as long as the node isn’t a
special “UI” node: those with a special user interface feature. For instance, you can call
Circle.ByCenterPointRadius, but it wouldn’t make much sense to call a Watch 3D node.
Regular nodes (most of your library), generally come in three types:
You’ll fnd that the library is organized with these categories in mind. Methods, or nodes, of
these three types are treated differently when invoked within a Code Block.
Create
The "Create" category will construct geometry from scratch. We input values in the code block
from left-to-right. These inputs are in the same order as the inputs on the node from top-to-
bottom:
Comparing the Line.ByStartPointEndPoint node and the corresponding syntax in the code
block, we get the same results.
Action
An action is something you do to an object of that type. Dynamo uses dot notation, common to
many coding languages, to apply an action to a thing. Once you have the thing, type a dot then
the name of the action. The action-type method’s input is placed in parentheses just like
create-type methods, only you don’t have to specify the frst input you see on the
corresponding node. Instead, we specify the element upon which we are performing the action:
1. The Point.Add node is an action-type node, so the syntax works a little differently.
2. The inputs are (1) the point, and (2) the vector to add to it. In a Code Block, we've
named the point (the thing) “pt”. To add a vector named “vec” to “pt”, we would write
pt.Add(vec), or: thing, dot, action. The Add action only has one input, or all the inputs
from the Point.Add node minus the frst one. The frst input for the Point.Add node is
the point itself.
Query
Query-type methods get a property of an object. Since the object itself is the input, you don’t
have to specify any inputs. No parentheses required.
How About Lacing?
Lacing with nodes is somewhat different from lacing with code block. With nodes, the user right
clicks on the node and selects the lacing option to perform. With code block, the user has
much more control as to how the data is structured. The code block shorthand method uses
replication guides to set how several one-dimensional lists should be paired. Numbers in
angled brackets "<>" defne the hierarchy of the resulting nested list: <1>,<2>,<3>, etc.
1. In this example, we use a shorthand to defne two ranges (more on shorthand in the
following section of this chapter). In short, 0..1; is equivalent to {0,1} and
-3..-7 is equivalent to {-3,-4,-5,-6,-7} . The result gives us lists of 2 x-values and
5 y-values. If we don’t use replication guides with these mismatched lists, we get a list
of two points, which is the length of the shortest list. Using replication guides, we can
fnd all of the possible combinations of 2 and 5 coordinates (or, a Cross Product).
2. Using the syntax Point.ByCoordinates(x_vals<1>,y_vals<2>); we get two lists with fve
items in each list.
3. Using the syntax Point.ByCoordinates(x_vals<2>,y_vals<1>); we get fve lists with two
items in each list.
With this notation, we can also specify which list will be dominant: 2 lists of 5 things or 5 lists of
2 things. In the example, changing the order of the replication guides makes the result a list of
rows of points or a list of columns of points in a grid.
Node to Code
While the code block methods above may take some getting used to, there is a feature in
Dynamo called "Node to Code" which will make the process easier. To use this feature, select
an array of nodes in your Dynamo graph, right-click on the canvas and select "Node to Code".
Dynamo condenses these nodes into a code block, with all of the inputs and outputs! Not only
is this a great tool for learning code block, but it also allows you to work with a more effcient
and parametric Dynamo graph. We'll conclude the exercise below by using "Node to Code", so
don't miss it.
Exercise
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix. Dynamo-Syntax_Attractor-
Surface.dyn
To show the power of code block, we are going to translate an existing attractor feld defnition
into code block form. Working with an existing defnition demonstrates how code block relates
to visual scripting, and is helpful for learning DesignScript syntax.
Begin by recreating the defnition in the image above (or by opening the sample fle).
1. Notice that the lacing on Point.ByCoordinates has been set to Cross Product.
2. Each point in a grid is moved up in the Z direction based on its distance to the
reference point.
3. A surface is recreated and thickened, creating a bulge in the geometry relative to the
distance to the reference point.
1. Starting from the beginning, let's defne the reference point frst:
Point.ByCoordinates(x,y,0); . We use the same Point.ByCoordinates syntax as is
specifed on the top of the reference point node.
2. The variables x and y are inserted into the code block so that we may update these
dynamically with sliders.
3. Add some sliders to the code block inputs which range from -50 to 50. This way, we
can span across the default Dynamo grid.
1. In the second line of the code block, we defne a shorthand to replace the number
sequence node: coordsXY = (-50..50..#11);
1. Now for the tricky part: We want to move the grid of points up based on their distance
to the reference point. First, let's call this new set of points transPts. And since a
translation is an action on an existing element, rather than using
Geometry.Translate... , we use gridPts.Translate .
2. Reading from the actual node on the canvas, we see that there are three inputs. The
geometry to translate is already declared because we are performing the action on
that element (with gridPts.Translate). The remaining two inputs will be inserted into
the parentheses of the function: direction and distance.
3. The direction is simple enough, we use a Vector.ZAxis() to move vertically.
4. The distance between the reference point and each grid point still needs to be
calculated, so we do this as an action to the reference point in the same manner:
refPt.DistanceTo(gridPts)
5. The fnal line of code gives us the translated points: transPts =
gridPts.Translate(Vector.ZAxis(),refPt.DistanceTo(gridPts));
1. We now have a grid of points with the appropriate data structure to create a Nurbs
Surface. We construct the surface using srf =
NurbsSurface.ByControlPoints(transPts);
1. And fnally, to add some depth to the surface, we construct a solid using solid =
srf.Thicken(5); In this case we thickened the surface by 5 units in the code, but we
could always declare this as a variable (calling it thickness for example) and then
control that value with a slider.
1. Start with the existing visual script from step 1 of the exercise. Select all of the nodes,
right click on the canvas, and select "Node to Code". Simple as that.
Dynamo has automated a text based version of the visual graph, lacing and all. Test this
out on your visual scripts and release the power of the code block!
Shorthand
There are a few basic shorthand methods in the code block which, simply put, make data
management a lot easier. We'll break down the basics below and discuss how this shorthand
can be used both for creating and querying data.
Code Block
Data Type Standard Dynamo
Equilvalent
Numbers
Strings
Sequences
Ranges
Concatenate Strings
Conditional Statements
Additional Syntax
Code Block
Node(s) Note
Equivalent
Any operator (+, +, &&, >=, !, Note that “Not” becomes “!” but the node is called
&&, >=, Not, etc.) etc. “Not” to distinguish from “Factorial”
Ranges
The method for defning ranges and sequences can be reduced to basic shorthand. Use the
image below as a guide to the ".." syntax for defning a list of numerical data with code block.
After getting the hang of this notation, creating numerical data is a really effcient process:
1. In this example, a number range is replaced by basic code block syntax defning the
beginning..end..step-size; . Represented numerically, we get: 0..10..1;
2. Notice that the syntax 0..10..1; is equivalent to 0..10; . A step-size of 1 is the
default value for the shorthand notation. So 0..10; will give a sequence from 0 to 10
with a step-size of 1.
3. The number sequence example is similar, except we use a "#" to state that we want
15 values in the list, rather than a list which goes up to 15. In this case, we are
defning: beginning..#ofSteps..step-size: . The actual syntax for the sequence is
0..#15..2
4. Using the "#" from the previous step, we now place it in the "step-size" portion of the
syntax. Now, we have a number range spanning from the "beginning" to the "end"
and the "step-size" notation evenly distributes a number of values between the two:
beginning..end..#ofSteps
Advanced Ranges
Creating advanced ranges allows us to work with list of lists in a simple fashion. In the
examples below, we're isolating a variable from the primary range notation, and creating
another range of that list.
1. Creating nested ranges, compare the notation with a "#" vs. the notation without. The
same logic applies as in basic ranges, except it gets a little more complex.
2. We can defne a sub-range at any place within the primary range, and notice that we
can have two sub-ranges as well.
3. By controlling the "end" value in a range, we create more ranges of differing lengths.
As a logic exercise, compare the two shorthands above and try to parse through how
subranges and the "#" notation drive the resultant output.
And manging with nested lists is a similar process. Be aware of the list order and recall using
multiple sets of square brackets:
Exercise
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix. Obsolete-Nodes_Sine-
Surface.dyn
In this exercise, we will fex our new shorthand skills to create a funky-cool eggshell surface
defned by ranges and formulas. During this exercise, notice how we use code block and
existing Dynamo nodes in tandem: we use the code block for the heavy data lifting while the
Dynamo nodes are visually laid out for legibility of the defnition.
Start by creating a surface by connecting the nodes above. Instead of using a number
node to defne width and length, double click on the canvas and type 100; into a code
block.
1. Defne a range between 0 and 1 with 50 divisions by typing 0..1..#50 into a code
block.
2. Connect the range into Surface.PointAtParameter, which takes u and v values
between 0 and 1 across the surface. Remember to change the Lacing to Cross
Product by right clicking on the Surface.PointAtParameter node.
In this step, we employ our frst function to move the grid of points up in the Z. This grid
will drive a generated surface based on the underlying function.
1. Add the visual nodes to the canvas as shown in the image above.
2. Rather than using a formula node, we use a code block with the line:
(0..Math.Sin(x*360)..#50)*5; . To quickly break this down, we're defning a range
with a formula inside of it. This formula is the Sine function. The sine function
receives degree inputs in Dynamo, so in order to get a full sine wave, we multiple our
x values (this is the range input from 0 to 1) by 360. Next we want the same number
of divisions as control grid points for each row, so we defne ffty subdivisions with
#50. Finally, the multiplier of 5 simply increases the amplitude of translation so that
we can see the effect in the Dynamo Preview.
1. While the previous code block worked fne, it wasn't completely parametric. We want
to dynamically drive its parameters, so we'll replace the line from the previous step
with (0..Math.Sin(x*360*cycles)..#List.Count(x))*amp; . This gives us the ability to
defne these values based on inputs.
1. By changing the sliders (ranging from 0 to 10), we get some interesting results.
1. By doing a transpose on the number range, we reverse the direction of the curtain
wave: transposeList = List.Transpose(sineList);
1. We get a distorted eggshell surface when we add the sineList and the tranposeList:
eggShellList = sineList+transposeList;
1. Changing the sliders again let's us calm the waters of this algorithm.
1. Last, let's query isolated parts of the data with the code block. To regenerate the
surface with a specifc range of points, add the code block above between the
Geometry.Translate and NurbsSurface.ByPoints node. This has the line of text:
sineStrips[0..15..1]; . This will select the frst 16 rows of points (out of 50).
Recreating the surface, we can see that we've generated an isolated portion of the
grid of points.
1. In the fnal step, to make this code block more parametric, we drive the query by
using a slider ranging from 0 to 1. We do this with this line of code: sineStrips[0..
((List.Count(sineStrips)-1)*u)]; . This may seem confusing, but the line of code
gives us a quick way to scale the length of the list into a multiplier between 0 and 1.
1. A value of .53 on the slider creates a surface just past the midpoint of the grid.
1. And as expected, a slider of 1 creates a surface from the full grid of points.
Looking at the resultant visual graph, we can highlight the code blocks and see each of
their functions.
1. The frst code block replaces the Number node.
2. The second code block replaces the Number Range node.
3. The third code block replaces the Formula node (as well as List.Transpose,
List.Count and Number Range).
4. The fourth code block queries a list of lists, replacing the List.GetItemAtIndex node.
Code Block Functions
Functions can be created in a code block and recalled elsewhere in a Dynamo defnition. This
creates another layer of control in a parametric fle, and can be viewed as a text-based version
of a custom node. In this case, the "parent" code block is readily accessible and can be located
anywhere on the graph. No wires needed!
Parent
The frst line has the key word “def”, then the function name, then the names of inputs in
parentheses. Braces defne the body of the function. Return a value with “return =”. Code
Blocks that defne a function do not have input or output ports because they are called from
other Code Blocks.
Children
Call the function with another Code Block in the same fle by giving the name and the same
number of arguments. It works just like the out-of-the-box nodes in your library.
FunctionName(in1,in2);
Exercise
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix. Functions_SphereByZ.dyn
In this exercise, we will make a generic defnition that will create spheres from an input list of
points. The radius of these spheres are driven by the Z property of each point.
Let's begin with a number range of ten values spanning from 0 to 100. Plug these into a
Point.ByCoordinates nodes to create a diagonal line.
1. Create a code block and introduce our defnition by using the line of code:
def sphereByZ(inputPt){
};
The inputPt is the name we've given to represent the points that will drive the
function. As of now, the function isn't doing anything, but we'll build up this function in
the steps to come.
1. Adding to the code block function, we place a comment and a sphereRadius variable
which queries the Z position of each point. Remember, inputPt.Z does not need
parenetheses as a method. This is a query of an existing element's properties, so no
inputs are necessary:
def sphereByZ(inputPt,radiusRatio)
{
//get Z Value, use it to drive radius of sphere
sphereRadius=inputPt.Z;
};
1. Now, let's recall the function we've created in another code block. If we double-click
on the canvas to create a new code block, and type in sphereB, we notice that
Dynamo suggest the sphereByZ function that we've defned. Your function has been
added to the intellisense library! Pretty cool.
1. Now we call the function and create a variable called Pt to plug in the points created
in the earlier steps:
sphereByZ(Pt)
2. We notice from the output that we have all null values. Why is this? When we defned
the function, we are calculating the sphereRadius variable, but we did not defne what
the function should return as an output. We can fx this in the next step.
1. An important step, we need to defne the output of the function by adding the line
return = sphereRadius; to the sphereByZ function.
2. Now we see that the output of the code block gives us the Z coordinates of each
point.
Let's create actual spheres now by editing the Parent function.
1. On the Point.ByCoordinates node, by changing the lacing from Shortest List to Cross
Product, we create a grid of points. The sphereByZ function is still in full effect, so the
points all create spheres with radii based on Z values.
1. And just to test the waters, we plug the original list of numbers into the X input for
Point.ByCoordinates. We now have a cube of spheres.
2. Note: if this takes a long time to calculate on your computer, try to change #10 to
something like #5.
1. Remember, the sphereByZ function we've created is a generic function, so we can
recall the helix from an earlier lesson and apply the function to it.
One fnal step: let's drive the radius ratio with a user defned parameter. To do this, we
need to create a new input for the function and also replace the 20 divider with a
parameter.
def sphereByZ(inputPt,radiusRatio)
{
//get Z Value, use it to drive radius of sphere
sphereRadius=inputPt.Z/radiusRatio;
//Defne Sphere Geometry
sphere=Sphere.ByCenterPointRadius(inputPt,sphereRadius);
//Defne output for function
return sphere;
};
2. Update the children code blocks by adding a ratio variable to the input:
sphereByZ(Pt,ratio);
Plug a slider into the newly created code block input and vary
the size of the radii based on the radius ratio.
Dynamo for Revit
While Dynamo is a fexible environment, designed to port into a wide range of programs, it was
originally created for use with Revit. A visual program creates robust options for a Building
Information Model (BIM). Dynamo offers a whole suite of nodes specifcally designed for Revit,
as well as third-party libraries from a thriving AEC community. This chapter focuses on the
basics of using Dynamo in Revit.
The Revit Connection
Dynamo for Revit extends buildin g information modeling with the data and logic environment
of a graphical algorithm editor. Its fexibility, coupled with a robust Revit database, offers a new
perspective for BIM.
This chapter focuses on the Dynamo workfows for BIM. Sections are primarily exercise-based,
since jumping right into a project is the best way to get familiar with a graphical algorithm editor
for BIM. But frst, let's talk about the beginnings of the program.
As both Revit and Dynamo continue to evolve, you may notice that the Revit version you are
working with is not compatible with the Dynamo for Revit version you have installed on your
machine. Below outlines which versions of Dynamo for Revit are compatible with Revit.
History of Dynamo
With a dedicated team of developers and a passionate community, the project has come a
long way from its humble beginnings.
Dynamo was originally created to streamline AEC workfows in Revit. While Revit creates a
robust database for every project, it can be diffcult for an average user to access this
information outside of the constraints of the interface. Revit hosts a comprehensive API
(Application Program Interface), allowing third-party developers to create custom tools. And
programmers have been using this API for years, but text-based scripting isn't accessible to
everyone. Dynamo seeks to democratize Revit data through an approachable graphical
algorithm editor.
Using the core Dynamo nodes in tandem with custom Revit ones, a user can substantially
expand parametric workfows for interoperability, documentation, analysis, and generation.
With Dynamo, tedious workfows can be automated while design explorations can thrive.
Running Dynamo in Revit
1. In a Revit project or family editor, navigate to Addins and click Dynamo. Take note:
Dynamo will run only in the fle in which it was opened.
1. When opening Dynamo in Revit, there is a new category called "Revit". This is a
comprehensive addition to the UI which offers nodes specifcally catering to Revit
workfows.*
*Note - By using the Revit-specifc family of nodes, the Dynamo graph will only work when
opening in Dynamo for Revit. If a Dynamo for Revit graph is opened in Dynamo Sandbox for
example, the Revit nodes will be missing.
Freezing Nodes
Since Revit is a platform which provides robust project management, parametric operations in
Dynamo can be complex and slow to calculate. If Dynamo is taking a long time to calculate
nodes, you may want to use the "freeze" node functionality in order to pause the execution of
Revit operations while you develop your graph. For more information on freezing nodes, check
out the "Freezing" section in the solids chapter.
Community
Since Dynamo was originally created for AEC, its large and growing community is a great
resource for learning from and connecting with experts in the industry. Dynamo’s community is
made of architects, engineers, programmers, and designers who all have a passion for sharing
and making.
Selecting
Revit is a data-rich environment. This gives us a range of selection abilities which expands far
beyond "point-and-click". We can query the Revit database and dynamically link Revit
elements to Dynamo geometry while performing parametric operations.
The Revit library in the UI offers a "Selection" category which enables multiple ways to
select geometry.
To select Revit elements properly, it's important to have a full-understanding of the Revit
element hierarchy. Want to select all the walls in a project? Select by category. Want to select
every Eames chair in your mid-century modern lobby? Select by family. Before jumping into an
exercise, let's do a quick review of the Revit hierarchy.
Revit Hierarchy
Remember the taxonomy from Biology? Kingdom, Phylum, Class, Order, Family, Genus,
Species? Revit elements are categorized in a similar manner. On a basic level, the Revit
hierarchy can be broken down into Categories, Families, Types*, and Instances. An instance is
an individual model element (with a unique ID) while a category defnes a generic group (like
"walls" or "foors"). With the Revit database organized in this manner, we can select one
element and choose all similar elements based on a specifed level in the hierarchy.
*Note - Types in Revit are defned differently from types in programming. In Revit, a type refers
to a branch of the hierarchy, rather than a "data type".
The three images below breakdown the main categories for Revit element selection in
Dynamo. These are great tools to use in combination, and we'll explore some of these in the
following exercises.
Point-and-click is the easiest way to directly select a Revit element. You can select a full
model element, or parts of its topology (like a face or an edge). This remains dynamically
linked to that Revit object, so when the Revit fle updates its location or parameters, the
referenced Dynamo element will update in the graph.
Dropdown menus create a list of all accessible elements in a Revit project. You can use
this to reference Revit elements which are not necessarily visible in a view. This is a great
tool for querying existing elements or creating new ones in a Revit project or family editor.
You can also select Revit element by specifc tiers in the Revit hierarchy. This is a
powerful option for customizing large arrays of data in preparation for documentation or
generative instantiation and customization.
With the three images above in mind, let's dive into an exercise which selects elements from a
basic Revit project in preparation for the parametric applications we'll create in the remaining
sections of this chapter.
Exercise
Download the example fles that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix.
1. Selecting.dyn
2. ARCH-Selecing-BaseFile.rvt
In this example Revit fle, we have three element types of a simple building. We're going
to use this as an example for selecting Revit elements within the context of the Revit
hierarchy:
1. Building Mass
2. Trusses (Adaptive Components)
3. Beams (Structural Framing)
What conclusions can we draw from the elements currently in the Revit project view? And
how far down the hierarchy do we need to go to select the appropriate elements? This will
of course become a more complex task when working on a large project. There are a lot
of options available: we can select elements by categories, levels, families, instances, etc.
1. Since we're working with a basic setup, let's select the building mass by choosing
"Mass" in the Categories dropdown node. This can be found in the Revit>Selection
tab.
2. The output of the Mass category is just the category itself. We need to select the
elements. To do this, we use the "All Elements of Category" node.
At this point, notice that we don't see any geometry in Dynamo. We've selected a Revit
element, but have not converted the element into Dynamo geometry. This is an important
separation. If you were to select a large number of elements, you don't want to preview all of
them in Dynamo because this would slow everything down. Dynamo is a tool to manage a
Revit project without necessarily performing geometry operations, and we'll look at that in the
next section of this chapter.
In this case, we're working with simple geometry, so we want to bring the geometry into the
Dynamo preview. The "BldgMass" in the watch node above has a green number* next to it.
This represents the element's ID and tells us that we are dealing with a Revit element, not
Dynamo geometry. The next step is to convert this Revit element into geometry in Dynamo.
1. Using the Element. Faces node, we get a list of surfaces representing each face of
the Revit Mass. We can now see the geometry in the Dynamo viewport and start to
reference the face for parametric operations.
Here's an alternative method. In this case, we're stepping away from selecting via the
Revit Hierarchy ("All Elements of Category") and electing to explicitly select geometry in
Revit.
1. Using the "Select Model Element" node, click the "select" (or "change") button. In the
Revit viewport, select the desired element. In this case, we're selecting the building
mass.
2. Rather than Element.Faces, we can select the full mass as one solid geometry using
Element.Geometry. This selects all of the geometry contained within that mass.
3. Using Geometry.Explode, we can get the list of surfaces again. These two nodes
work the same as Element.Faces but offer alternative options for delving into the
geometry of a Revit element.
1. Using some basic list operations, we can query a face of interest.
2. First, the List.Count node reveals that we're working with 23 surfaces in the mass.
3. Referencing this number, we change the Maximum value of an integer slider to "22".
4. Using List.GetItemAtIndex, we input the lists and the integer slider for the index.
Sliding through with the selected, we stop when we get to index 9 and have isolated
the main facade hosts the trusses.
1. The previous step was a little cumbersome. We can do this much faster with the
"Select Face" node. This allows us to isolate a face that is not an element itself in the
Revit project. The same interaction applies as "Select Model Element", except we
select the surface rather than the full element.
Suppose we want to isolate the main facade walls of the building. We can use the "Select
Faces" node to do this. Click the "Select" button and then select the four main facades in
Revit.
1. After selecting the four walls, make sure you click the "Finish" button in Revit.
1. The faces are now imported into Dynamo as surfaces.
1. Now, let's take a look at the beams over the atrium. Using the "Select Model Element"
node, select one of the beams.
2. Plug the beam element into the Element.Geometry node and we now have the beam
in the Dynamo viewport.
3. We can zoom in on the geometry with a Watch3D node (if you don't see the beam in
Watch 3D, right click and hit "zoom to ft").
A question that may come up often in Revit/Dynamo workfows: how do I select one
element and get all similar elements? Since the selected Revit element contains all of its
hierarchical information, we can query its family type and select all elements of that type.
*Note - a family symbol is Revit API terminology for family type. Since this may cause some
confusion, it will be updated in upcoming releases.
1. To select the remaining beams, we use the "All Elements of Family Type" node.
2. The watch node shows that we've selected fve revit elements.
In any case, if we were to import 500 beams, do we need all of the surfaces to perform the
intended parametric operation? Or can we extract basic information from the beams and
perform generative tasks with fundamental geometry? This is a question that we'll keep in mind
as we walk through this chapter. For example, let's take a look at the truss system:
Using the same graph of nodes, select the truss element rather than the beam element.
Before doing this, delete the Element.Geometry from the previous step.
1. In the Watch node, we can see that we have a list of adaptive components selected
from Revit. We want to extract the basic information, so we're start with the adaptive
points.
2. Plug the "All Elements of Family Type" node into the "AdaptiveComponent.Location"
node. This gives us a list of lists, each with three points which represent the adaptive
point locations.
3. Connecting a "Polygon.ByPoints" node returns a polycurve. We can see this in the
Dynamo viewport. By this method, we've visualized the geometry of one element and
abstracted the geometry of the remaining array of elements (which could be larger in
number than this example).
*Tip: if you click on the green number of a Revit element in Dynamo, the Revit viewport will
zoom to that element.
Editing
A powerful feature of Dynamo is that you can edit parameters on a parametric level. For
example, a generative algorithm or the results of a simulation can be used to drive the
parameters of an array of elements. This way, a set of instances from the same family can
have custom properties in your Revit project.
1. Instance parameters defne the aperture of the panels on the roof surface, ranging
from an Aperture Ratio of 0.1 to 0.4.
2. Type-based parameters are applied to every element on the surface because they
are the same family type. The material of each panel, for example, can be driven by a
type-based parameter.
1. If you've set up a Revit family before, remember that you have to assign a parameter
type (string, number, dimension, etc.) Be sure to use the correct data type when
assigning parameters from Dynamo.
2. You can also use Dynamo in combination with parametric constraints defned in a
Revit family's properties.
As a quick review of parameters in Revit, we recall that there are type parameters and instance
parameters. Both can be edited from Dynamo, but we'll work with instance parameters in the
exercise below.
Note: As you discover the wide-reaching application of editing parameters, you may want to
edit a large quantity of elements in Revit with Dynamo. This can be a computationally
expensive operation, meaning that it can be slow. If you're editing a large number of elements,
you may want to use the "freeze" node functionality in order to pause the execution of Revit
operations while you develop your graph. For more information on freezing nodes, check out
the "Freezing" section in the solids chapter.
Units
For a quick conversion of units, use the "Convert Between Units" node. This is a handy
tool for converting Length, Area, and Volume units on the fy.
Exercise
Download the example fles that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix.
1. Editing.dyn
2. ARCH-Editing-BaseFile.rvt
This exercise focuses on editing Revit elements without performing geometric operation in
Dynamo. We're not importing Dynamo geometry here, just editing parameters in a Revit
project. This exercise is basic, and to the more advanced Revit users, notice that these are
instance parameters of a mass, but the same logic can be applied to an array of elements to
customize on a large scale. This is all done with the "Element.SetParameterByName" node.
Begin with the example Revit fle for this section. We've removed the structural elements
and adaptive trusses from the previous section. In this exercise, we will focus on a
parametric rig in Revit and manipulating in Dynamo.
1. Selecting the building in Mass in Revit, we see an array of instance parameters in the
properties panel.
1. Select the building mass with the "Select Model Element" node.
2. We can query all of the parameters of this mass with the "Element.Parameters" node.
This includes type and instance parameters.
1. Reference the Element.Parameters node to fnd target parameters. Or, we can view
the properties panel from the previous step to choose which parameter names we
want to edit. In this case, we are looking for the parameters which affect the large
geometric moves on the building mass.
2. We will make changes to the Revit element using the Element.SetParameterByName
node.
3. Using the code block, we defne a list of these parameters, with quotes around each
item to denote a string. We can also use the List.Create node with a series of "string"
nodes connected to multiple inputs. Code block is simply faster and easier. Just make
sure that the string matches the exact name in Revit, case-specifc:
{"BldgWidth","BldgLength","BldgHeight", "AtriumOffset", "InsideOffset","LiftUp"};
1. We also want to designate values for each parameter. Add six "integer sliders" to the
canvas and rename to the corresponding parameter in the list. Also, set the values of
each slider to the image above. In order from top-to-bottom: 62,92,25,22,8,12
2. Defne another code block with a list of the same length as the parameter names. In
this case, we name variables (without quotes) which create inputs for the code block.
Plug the sliders into each respective input: {bw,bl,bh,ao,io,lu};
3. Connect the code block to the "Element.SetParameterByName"* node. With run
automatically checked, we will automatically see results.
*Note - this demonstration works with instance parameters, but not type parameters.
Just as in Revit, many of these parameters are dependent on each other. There are of course
combinations where the geometry may break. We can remedy this issue with defned formulas
in the parameter properties, or we can setup a similar logic with math operations in Dynamo
(this is an additional challenge if you'd like to expand on the exercise).
Creating
You can create an array of Revit elements in Dynamo with full parametric control. The Revit
nodes in Dynamo offer the ability to import elements from generic geometries to specifc
category types (like walls and foors). In this section, we'll focus on importing parametrically
fexible elements with adaptive components.
Adaptive Components
An adaptive component is a fexible family category which lends itself well to generative
applications. Upon instantiation, you can create a complex geometric element which is driven
by the fundamental location of adaptive points.
An example of a three-point adaptive component in the family editor. This generates a
truss which is defned by the position of each adaptive point. In the exercise below, we'll
use this component to generate a series of trusses across a facade.
Principles of Interoperability
The adaptive component is a good example for best practices of interoperability. We can
create an array of adaptive components by defning the fundamental adaptive points. And,
when transferring this data to other programs, we have the ability to reduce the geometry to
simple data. Importing and exporting with a program like Excel follows a similar logic.
Suppose a facade consultant wants to know the location of the truss elements without needing
to parse through fully articulated geometry. In preparation for fabrication, the consultant can
reference the location of adaptive points to regenerate geometry in a program like Inventor.
The workfow we'll setup in the exercise below allows us to access all of this data while
creating the defnition for Revit element creation. By this process, we can merge
conceptualization, documentation, and fabrication into a seamless workfow. This creates a
more intelligent and effcient process for interoperability.
Multiple Elements and Lists
The exercise below will walk through how Dynamo references data for Revit element creation.
To generate multiple adaptive components, we defne a list of lists, where each list has three
points representing each point of the adaptive component. We'll keep this in mind as we
manage the data structures in Dynamo.
Exercise
Download the example fles that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix.
1. Creating.dyn
2. ARCH-Creating-BaseFile.rvt
Beginning with the example fle from this section (or continuing with the Revit fle from the
previous session), we see the same Revit mass.
We've used the "Select Model Element" and "Select Face" nodes, now we're taking one
step further down in the geometry hierarchy and using "Select Edge". With the Dynamo
solver set to run "Automatic", the graph will continually update to changes in the Revit fle.
The edge we are selecting is tied dynamically to the Revit element topology. As long as
the topology* does not change, the connection remains linked between Revit and
Dynamo.
1. Select the top most curve of the glazing facade. This spans the full length of the
building. If you're having trouble selecting the edge, remember to choose the
selection in Revit by hovering over the edge and hitting "Tab" until the desired edge is
highlighted.
2. Using two "Select Edge" nodes, select each edge representing the cant at the middle
of the facade.
3. Do the same for the bottom edges of the facade in Revit.
4. The Watch nodes reveal that we now have lines in Dynamo. This is automatically
converted to Dynamo geometry since the edges themselves are not Revit elements.
These curves are the references we'll use to instantiate adaptive trusses across the
facade.
*Note - to keep a consistent topology, we're referring to a model that does not have additional
faces or edges added. While parameters can change its shape, the way in which it is built
remains consistent.
We frst need to join the curves and merge them into one list. This way we can "group" the
curves to perform geometry operations.
1. Create a list for the two curves at the middle of the facade.
2. Join the two curves into a Polycurve by plugging the List.Create component into a
Polycurve.ByJoinedCurves node.
3. Create a list for the two curves at the bottom of the facade.
4. Join the two curves into a Polycurve by plugging the List.Create component into a
Polycurve.ByJoinedCurves node.
5. Finally, join the three main curves (one line and two polycurves) into one list.
We want to take advantage of the top curve, which is a line, and represents the full span
of the facade. We'll create planes along this line to intersect with the set of curves we've
grouped together in a list.
1. Plug an integer slider into the input for the code block. As you could have guessed, this
will represent the number of trusses. Notice that the slider controls the number of items in
the range defned from 0 to 1.
2. Plug the code block into the param input of a "Curve.PlaneAtParameter" node, and plug
the top edge into the curve input. This will give us ten planes, evenly distributed across the
span of the facade.
A plane is an abstract piece of geometry, representing a two dimensional space which is
infnite. Planes are great for contouring and intersecting, as we are setting up in this step.
1. Using the Geometry.Intersect node (note the cross product lacing), plug the
Curve.PlaneAtParameter into the entity input of the Geometry.Intersect node. Plug
the main List.Create node into the geometry input. We now see points in the Dynamo
viewport representing the intersection of each curve with the defned planes.
Notice the output is a list of lists of lists. Too many lists for our purposes. We want to do a
partial fatten here. We need to take one step down on the list and fatten the result. To do
this, we use the List.Map operation, as discussed in the list chapter of the primer.
And for the fnal test, by selecting the mass in Revit and editing instance parameters, we
can change the form of the building and watch the truss follow suit. Remember, this
Dynamo graph has to be open in order to see this update, and the link will be broken as
soon as it's closed.
DirectShape Elements
Another method for importing parametric Dynamo geometry into Revit is with DirectShape. In
summary, the DirectShape element and related classes support the ability to store externally
created geometric shapes in a Revit document. The geometry can include closed solids or
meshes. DirectShape is primarily intended for importing shapes from other data formats such
as IFC or STEP where not enough information is available to create a "real" Revit element.
Like the IFC and STEP workfow, the DirectShape functionality works well with importing
Dynamo created geometries into Revit projects as real elements.
Let's walk through and exercise for importing Dynamo geometry as a DirectShape into our
Revit project. Using this method, we can assign an imported geometry's category, material,
and name - all while maintaining a parametric link to our Dynamo graph.
Exercise
Download the example fles that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix.
1. DirectShape.dyn
2. ARCH-DirectShape-BaseFile.rvt
Begin by opening the sample fle for this lesson - ARCH-DirectShape-BaseFile.rvt.
1. In the 3D view, we see our building mass from the previous lesson.
2. Along the edge of the atrium is one reference curve, we'll use this as a curve to
reference in Dynamo.
3. Along the opposing edge of the atrium is another reference curve which we'll
reference in Dynamo as well.
1. To reference our geometry in Dynamo, we'll use Select Model Element for each
member in Revit. Select the mass in Revit and import the geometry into Dynamo by
Using Element.Faces - the mass should now be visible in your Dynamo preview.
2. Import one reference curve into Dynamo by using Select Model Element and
CurveElement.Curve.
3. Import the other reference curve into Dynamo by using Select Model Element and
CurveElement.Curve.
1. Zooming out and panning to the right in the sample graph, we see a large group of
nodes - these are geometric operations which generate the trellis roof structure
visible in the Dynamo preview. These nodes are generating using the Node to Code
functionality as discussed in the code block section of the primer.
2. The structure is driven by three major parameters - Diagonal Shift, Camber, and
Radius.
Zooming a close-up look of the parameters for this graph. We can fex these to get
different geometry outputs.
1. Dropping the DirectShape.ByGeometry node onto the canvas, we see that it has four
inputs: geometry, category, material , and name.
2. Geometry will be the solid created from the geometry creation portion of the graph
3. The category input is chosen using the dropdown Categories node. In this case we'll
use "Structural Framing".
4. The material input is selected through the array of nodes above - although it can be
more simply defned as "Default" in this case.
After running Dynamo, back in Revit, we have the imported geometry on the roof in our
project. This is a structural framing element, rather than a generic model. The parametric
link to Dynamo remains intact.
Customizing
While we previously looked at editing a basic building mass, we want to dive deeper into the
Dynamo/Revit link by editing a large number of elements in one go. Customizing on a large
scale becomes more complex as data structures require more advanced list operations.
However, the underlying principles behind their execution is fundamentally the same. Let's
study some opportunities for analysis from a set of adaptive components.
Point Location
Suppose we've created a range of adaptive components and want to edit parameters based on
their point locations. The points, for example, could drive a thickness parameter which is
related to the area of the element. Or, they could drive an opacity parameter related to solar
exposure throughout the year. Dynamo allows the connection of analysis to parameters in a
few easy steps, and we'll explore a basic version in the exercise below.
Query the adaptive points of a selected adaptive component by using the
AdaptiveComponent.Locations node. This allows us to work with an abstracted version of
a Revit element for analysis.
By extracting the point location of adaptive components, we can run a range of analysis for that
element. A four-point adaptive component will allow you to study the deviation from plane for a
given panel for example.
Using Dynamo, the point locations of adaptive components can be used to create a best-ft
plane each element. We can also query the sun position in the Revit fle and study the plane's
relative orientation to the sun in comparison to other adaptive components. Let's set that up in
the exercise below by creating an algorithmic roofscape.
Exercise
Download the example fles that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix.
1. Customizing.dyn
2. ARCH-Customizing-BaseFile.rvt
This exercise will expand on the techniques demonstrated in the previous section. In this case,
we are defning a parametric surface from Revit elements, instantiating four-point adaptive
components and then editing them based on orientation to the sun.
1. Beginning by selecting two edges with the "Select Edge" node. The two edges are
the long spans of the atrium.
2. Combine the two edges into one list with the List.Create node.
3. Create a surface between the two edges with a Surface.ByLoft.
1. Using code block, defne a range from 0 to 1 with 10 evenly spaced values:
0..1..#10;
2. Plug the code block into the u and v inputs of a Surface.PointAtParameter node, and
plug the Surface.ByLoft node into the surface input. Right click the node and change
the lacing to Cross Product. This will give a grid of points on the surface.
This grid of points serves as the control points for a parametrically defned surface. We want to
extract the u and v positions of each one of these points so that we can plug them into a
parametric formula and keep the same data structure. We can do this by querying the
parameter locations of the points we just created.
With the parametric surface, we want to defne a way to panelize it in order to array four-point
adaptive components. Dynamo does not have out-of-the-box functionality for surface
panelization, so we can look to the community for helpful Dynamo packages.
1. Go to Packages>Search for a Package...
2. Search for "LunchBox" and download "LunchBox for Dynamo". This is a really helpful
set of tools for geometry operations such as this.
1. After downloading, you now have full access to the LunchBox suite. Search for "Quad
Grid" and select "LunchBox Quad Grid By Face". Plug the parametric surface into the
surface input and set the U and V divisions to 15. You should see a quad-paneled
surface in your Dynamo preview.
If you're curious about its setup, you can double click on the Lunch Box node and see how
it's made.
Back in Revit, let's take a quick look at the adaptive component we're using here. No need
to follow along, but this is the roof panel we're going to instantiate. It is a four-point
adaptive component which is a crude representation of an ETFE system. The aperture of
the center void is on a parameter called "ApertureRatio".
1. We're about to instantiate a lot of geometry in Revit, so make sure to turn the
Dynamo solver to "Manual".
2. Add a Family Types node to the canvas and select "ROOF-PANEL-4PT".
3. Add an AdaptiveComponent.ByPoints node to the canvas, connect Panel Pts from
the "LunchBox Quad Grid by Face" output into the points input. Connect the Family
Types node to the familySymbol input.
4. Hit Run. Revit will have to think for a bit while the geometry is being created. If it
takes too long, reduce the code block's '15' to a lower number. This will reduce the
number of panels on the roof.
Note: If Dynamo is taking a long time to calculate nodes, you may want to use the "freeze"
node functionality in order to pause the execution of Revit operations while you develop your
graph. For more information on freezing nodes, check out the "Freezing" section in the solids
chapter.
Analysis
1. Continuing from the previous step, let's go further and drive the aperture of each
panel based on its exposure to the sun. Zooming into Revit and select one panel, we
see in the properties bar that there is a parameter called "Aperture Ratio". The family
is setup so that the aperture ranges, roughly, from 0.05 to 0.45.
1. If we turn on the solar path, we can see the current sun location in Revit.
Zooming in, we see that the ETFE panels are more closed as the face the sun. Our target
here is to reduce overheating from solar exposure. If we wanted to let in more light based
on solar exposure, we just have to switch the domain on Math.RemapRange.
Documenting
Editing parameters for documentation follows suit with the lessons learned in prior sections. In
this section, we'll look at editing parameters which don't affect the geometric properties of an
element, but instead prepare a Revit fle for documentation.
Deviation
In the exercise below, we'll use a basic deviation from plane node to create a Revit sheet for
documentation. Each panel on our parametrically defned roof structure has a different value
for deviation, and we want to call out the range of values using color and by scheduling out the
adaptive points to hand off to a facade consultant, engineer, or contractor.
The deviation from plane node will calculate the distance that the set of four points varies
from the best-ft plane between them. This is a quick and easy way to study
constructability.
Exercise
Download the example fles that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix.
1. Documenting.dyn
2. ARCH-Documenting-BaseFile.rvt
Start with the Revit fle for this section (or continue from the previous section). This fle has an
array of ETFE panels on the roof. We'll reference these panels for this exercise.
Back in Revit we can kind of make sense of the change in aperture across the surface.
Zooming in, it becomes more clear that the closed panels are weighted towards the
corners of the surface. The open corners are towards the top. The corners represent
areas of larger deviation while bulge has minimal curvature, so this makes sense.
Scheduling
1. Selecting one ETFE panel in Revit, we see that there are four instance parameters,
XYZ1, XYZ2, XYZ3, and XYZ4. These are all blank after they're created. These are
text-based parameters and need values. We'll use Dynamo to write the adaptive point
locations to each parameter. This helps interoperability if the geometry needs to be
sent to an engineer of facade consultant.
In a sample sheet, we have a large, empty schedule. The XYZ parameters are shared
parameters in the Revit fle, which allows us to add them to the schedule.
Zooming in, the XYZ parameters are yet to be flled in. The frst two parameters are taken
care of by Revit.
To write in these values, we'll do a complex list operation. The graph itself is simple, but
the concepts build heavily from the list mapping as discussed in the list chapter.
Each ETFE panel now has the XYZ coordinates written for each adaptive point,
representing the corners of each panel for fabrication.
Dictionaries in Dynamo
Dictionaries represent a collection of data that is related to another piece of data known as a
key. Dictionaries expose the ability to search for, delete and insert data into a collection.
Essentially, we can think of a dictionary as a really smart way to look something up.
While dictionary functionality has been available in Dynamo for some time, Dynamo 2.0
introduces a new way of managing this data type.
What is a dictionary?
A dictionary is a data type composed of a collection of key-value pairs where each key is
unique in each collection. A dictionary has no order and basically you can “look things up”
using a key instead of an index value like in a list. In Dynamo 2.0, keys can only be
strings.
What is a list?
A list is a data type composed of a collection of ordered values. In Dynamo, lists use
integers as index values.
The separation of dictionaries from lists introduces dictionaries as a frst-class citizen that
you can use to quickly and easily store and lookup values without needing to remember
an index value or maintain a strict list structure throughout your workfow. During user
testing, we saw a signifcant reduction in graph size when dictionaries were utilized
instead of several GetItemAtIndex nodes.
Syntax changes have occurred that change how you will initialize and work with
dictionaries and lists in code blocks.
Dictionaries use the following syntax {key:value}
Lists use the following syntax [value,value,value]
New nodes have been introduced to the library to help you create, modify, and query
dictionaries.
Lists created in 1.x code blocks will automatically migrated on load of the script to the
new list syntax that uses square brackets [ ] instead of curly brackets { }
In computer science, Dictionaries - like lists- are collections of objects. While lists are in a
specifc order, dictionaries are unordered collections. They are not reliant on sequential
numbers (indices), instead, they utilize keys.
In the image below we demonstrate a potential use case of a dictionary. Often times
dictionaries are used to relate two pieces of data that might not have a direct correlation. In our
case, we are connecting the Spanish version of a word to the English version for later lookup.
Dictionary Nodes
Dynamo 2.0 exposes a variety of Dictionary nodes for our use. This includes create, action,
and query nodes.
Dictionary.ByKeysValues will create a dictionary with the supplied values and keys. (The
number of entries will be whatever the shortest list input is)
Dictionary.Components will produce the components of the input dictionary. (This is the
reverse of the create node.)
Dictionary.RemoveKeys will produce a new dictionary object with the input keys removed.
Dictionary.SetValueAtKeys will produce a new dictionary based on the input keys and the
values to replace the current value at the corresponding keys.
Dictionary.ValueAtKey will return the value at the input key.
Dictionary.Count will tell you how many key value pairs are in the dictionary.
Dictionary.Keys will return what keys are currently stored in the dictionary.
Dictionary.Values will return what values are currently stored in the dictionary.
Overall relating data with dictionaries is a magnifcent alternative to the old method of working with
indices and lists.
Dictionaries in Code Blocks
Not only does Dynamo 2.0 introduce the nodes previously discussed for dictionaries, there is
new functionality in code blocks for this as well!
You can use syntax like below or DesignScript-based representations of the nodes.
Since a dictionary is an object type in Dynamo we can commit the following actions upon it.
Maintaining these sort of interactions becomes especially useful when relating Revit data to
strings. Next, we will look at some Revit use-cases.
Dictionaries - Revit Use-Cases
Have you ever wanted to look up something in Revit by a piece of data that it has?
In the image above we are collecting all of the rooms in the Revit model, getting the index
of the room we want (by room number), and fnally grabbing the room at the index.
We choose the Revit category we want to work with, (In this case, we are working
with rooms).
We tell Dynamo to collect all of those elements
Next, we need to decide what keys we are going to use to look up this data by. (Information on
keys can be found on the section, 9-1 What is a dictionary?).
Lastly, we can retrieve a room from the dictionary with its room number now.
String will be the key that we are using to look up an object from the dictionary.
Dictionary.ValueAtKey will obtain the object from the dictionary now.
Using this same dictionary logic, we can create dictionaries with
grouped objects as well. If we wanted to look up all rooms at a given
level we can modify the above graph as follows.
Rather than using the room number as the key, we can now use a parameter value,
(in this case we will use level).
Now, we can group the rooms by the level that they reside on.
With the elements grouped by the level, we can now use the shared keys (unique
keys) as our key for our dictionary, and the lists of rooms as the elements.
Lastly, using the levels in the Revit model, we can look up which rooms reside on that
level in the dictionary. Dictionary.ValueAtKey will take the level name and return the
room objects at that level.
The opportunities for Dictionary use are really endless. The ability to relate your BIM data in
Revit to the element itself poses a variety of use cases.
Custom Nodes
Out of the box, Dynamo has a lot of functionality stored in its Library of Nodes. For those
frequently used routines or that special graph you want to share with the community, Custom
Nodes are a great way to extend Dynamo even further.
Custom Nodes
Dynamo offers many core nodes for a wide-range of visual programming tasks. Sometimes a
quicker, more elegant, or more easily shared solution is to build your own nodes. These can be
reused among different projects, they make your graph clearer and cleaner, and they can be
pushed to the package manager and shared with the global Dynamo community.
Adapting to Change
When you have multiple copies of a custom node in your graph, you can update all of them by
editing the base custom node. This allows you to update your graph seamlessly by adapting to
any changes that may occur in workfow or design.
Work Sharing
Arguably the best feature of custom nodes is their work sharing capabilities. If a "power user"
creates a complex Dynamo graph and hands it off to a designer who is new to Dynamo, he/she
can condense the graph to the bare essentials for design interaction. The custom node can be
opened to edit the internal graph, but the "container" can be kept simple. With this process,
custom nodes allow Dynamo users to design a graph that is clean and intuitive.
Many Ways to Build a Node
There are a wide variety of ways to build custom nodes in Dynamo. In the examples in this
chapter, we'll create custom nodes directly from the Dynamo UI. If you are a programmer and
you are interested in C# or Zero-Touch formatting, you can reference this page on the Dynamo
Wiki for a more in-depth review.
To create a Custom Node from scratch, Launch Dynamo and select Custom Node, or type
Ctrl + Shift + N from the canvas.
Assign a name, description, and category in the Custom Node Properties dialog.
1. Name: Percentage
2. Description: Calculate the percentage of one value in relation to another.
3. Category: Core.Math
This will open a canvas with a yellow background, indicating that you are working inside a
custom node. In this canvas you have access to all of the core Dynamo nodes, as well as
the Input and Output nodes, which label the data fowing into and out of the custom node.
They can be found in Core>Input.
1. Inputs: input nodes create input ports on the custom node. The syntax for an input
node is input_name : datatype = default_value(optional).
2. Outputs: Similar to inputs, these will create and name output ports on the custom
node.
Consider adding a Custom Comment to your Input and Output ports to hint at
the Input and Output types. This is discussed in more detail in the Creating Custom
Nodes section.
You can save this custom node as a .dyf (as opposed to the standard .dyn) fle and it will
automatically be added to your session and future sessions. You will fnd the custom node in
your library in the category that is specifed in the custom node's properties.
Left: The Core > Math category of the default library
Moving Forward
Now that we've created our frst custom node, the next sections will dive deeper into custom
node functionality and how to publish generic workfows. In the following section, we'll look at
developing a custom node that transfers geometry from one surface to another.
Creating a Custom Node
Dynamo offers several different methods for creating custom nodes. You can build custom
nodes from scratch, from an existing graph, or explicitly in C#. In this section we will cover
building a custom node in the Dynamo UI from an existing graph. This method is ideal for
cleaning up the workspace, as well as packaging a sequence of nodes to reuse elsewhere.
Let’s start by creating a graph that we want to nest into a custom node. In this example, we will
create a graph that maps polygons from a base surface to a target surface, using UV
coordinates. This UV mapping process is something we use frequently, making it a good
candidate for a custom node. For more information on surfaces and UV space, see section 5.5.
The complete graph is UVmapping_Custom-Node.dyn from the .zip fle downloaded above.
1. Code Block: Create a range of 10 numbers between 45 and negative 45 using a code
block.
2. Point.ByCoordinates: Connect the output of the Code Block to the ‘x’ and ‘y’ inputs
and set the lacing to cross-reference. You should now have a grid of points.
3. Plane.ByOriginNormal: Connect the ‘Point’ output to the ‘origin’ input to create a
plane at each of the points. The default normal vector of (0,0,1) will be used.
4. Rectangle.ByWidthLength: Connect the planes from the previous step into the ‘plane’
input, and use a Code Block with a value of 10 to specify the width and length.
You should now see a grid of rectangles. Let’s map these rectangles to a target surface using
UV coordinates.
1. Polygon.Points: Connect the Rectangle output from the previous step to the ‘polygon’
input to extract the corner points of each rectangle. These are the points that we will
map to the target surface.
2. Rectangle.ByWidthLength: Use a Code Block with a value of 100 to specify the width
and length of a rectangle. This will be the boundary of our base surface.
3. Surface.ByPatch: Connect the Rectangle from the previous step to the ‘closedCurve’
input to create a base surface.
4. Surface.UVParameterAtPoint: Connect the ‘Point’ output of the Polygon.Points node
and the ‘Surface’ output of the Surface.ByPatch node to return the UV parameter at
each point.
Now that we have a base surface and a set of UV coordinates, we can import a target surface
and map the points between surfaces.
1. File Path: Select the fle path of the surface you want to import. The fle type should
be .SAT. Click the "Browse..." button and navigate to the UVmapping_srf.sat fle from
the .zip fle downloaded above.
2. Geometry.ImportFromSAT: Connect the fle path to import the surface. You should
see the imported surface in the geometry preview.
3. UV: Connect the UV parameter output to a UV.U and a UV.V node.
4. Surface.PointAtParameter: Connect the imported surface as well as the u and v
coordinates. You should now see a grid of 3D points on the target surface.
The fnal step is to use the 3D points to construct rectangular surface patches.
1. PolyCurve.ByPoints: Connect the points on the surface to construct a polycurve
through the points.
2. Boolean: Add a Boolean to the workspace and connect it to the ‘connectLastToFirst’
input and toggle to True to close the polycurves. You should now see rectangles
mapped to the surface.
3. Surface.ByPatch: Connect the polycurves to the ‘closedCurve’ input to construct
surface patches.
Now let’s select the nodes that we want to nest into a Custom Node, thinking about what we
want to be the inputs and outputs of our node. We want our Custom Node to be as fexible as
possible, so it should be able to map any polygons, not just rectangles.
Select the above nodes (beginning with Polygon.Points), right click on the workspace and
select ‘node from selection’.
In the Custom Node Properties dialog, assign a name, description, and category to the
Custom Node.
The Custom Node has considerably cleaned up the workspace. Notice that the inputs and
outputs have been named based on the original nodes. Let’s edit the Custom Node to
make the names more descriptive.
Double click the Custom Node to edit it. This will open a workspace with a yellow
background representing the inside of the node.
1. Inputs: Change the input names to baseSurface and targetSurface.
2. Outputs: Add an additional output for the mapped polygons.
We can also add to the robustness of the Custom Node by adding in Custom Comments.
Comments can help to hint at the input and output types or explain the functionality of the
node. Comments will appear when the user hovers over an input or output of a Custom Node.
Double click the Custom Node to edit it. This will re-open the yellow background
workspace.
1. Begin editing the Input Code Block. To start a Comment, type "//" followed by the
comment text. Type anything that may help to clarify the Node - Here we will describe
the targetSurface.
2. Let's also set the default value for the inputSurface by setting the input type equal to
a value. Here, we will set the default value to the original Surface.ByPatch set.
Comments can also be applied to the Outputs. Begin editing the text in the Output Code
Block. To start a Comment, type "//" followed by the comment text. Here we will clarify the
Polygons and the surfacePatches Outputs by adding a more in-depth description.
>
Adding to Your Library
We've just created a custom node and applied it to a specifc process in our Dynamo graph.
And we like this node so much, we want to keep it in our Dynamo library to reference in other
graphs. To do this, we'll publish the node locally. This is a similar process to publishing a
package, which we'll walk through in more detail in the next chapter.
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix. PointsToSurface.dyf
After opening the PointsToSurface custom node, we see the graph above in the Dynamo
Custom Node Editor. You can also open up a custom node by double clicking on it in the
Dynamo Graph Editor.
1. To Publish a custom node locally, simply right click on the canvas and select "Publish
This Custom Node..."
Fill out the relevant information similar to the image above and select "Publish Locally"..
Note that the Group feld defnes the main element accessible from the Dynamo menu.
Choose a folder to house all of the custom nodes that you plan on publishing locally.
Dynamo will check this folder each time it loads, so make sure the folder is in a permanent
place. Navigate to this folder and choose "Select Folder". Your Dynamo node is now
published locally, and will remain in your Dynamo Toolbar each time you load the
program!
1. To check on the custom node folder location, go to Settings > Manage Node and
Package Paths...
In this window we see two paths: AppData\Roaming\Dynamo... refers to the default
location of Dynamo Packages installed online. Documents\DynamoCustomNodes... refers
to the location of custom nodes we've published locally. *
1. You may want to move your local folder path down in the list order above (by
selecting the folder path and clicking on the down arrow to the left of the path names).
The top folder is the default path for package installs. So by keeping the default
Dynamo package install path as the default folder, online packages will be separated
from your locally published nodes.*
We switched the order of the path names in order to have Dynamo's default path as the
package install location.
Navigating to this local folder, we can fnd the original custom node in the ".dyf" folder,
which is the extension for a Dynamo Custom Node fle. We can edit the fle in this folder
and the node will update in the UI. We can also add more nodes to the main
DynamoCustomNode folder and Dynamo will add them to your library at restart!
Dynamo will now load each time with "PointsToSurface" in the "DynamoPrimer" group of
your Dynamo library.
Python
Python is a widely used programming language whose popularity has a lot to do with its style
of syntax. It's highly readable, which makes it easier to learn than many other languages.
Python supports modules and packages, and can be embedded into existing applications. The
examples in this section assume a basic familiarity with Python. For information about how to
get up and running with Python, a good resource is the "Getting Started" page on Python.org.
Visual Program:
Textual Program:
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
solid = IN[0]
seed = IN[1]
xCount = IN[2]
yCount = IN[3]
solids = []
yDist = solid.BoundingBox.MaxPoint.Y-solid.BoundingBox.MinPoint.Y
xDist = solid.BoundingBox.MaxPoint.X-solid.BoundingBox.MinPoint.X
for i in xRange:
for j in yRange:
fromCoord = solid.ContextCoordinateSystem
toCoord =
fromCoord.Rotate(solid.ContextCoordinateSystem.Origin,Vector.ByCoordinates(0,0,1),(90*
(i+j%val)))
vec = Vector.ByCoordinates((xDist*i),(yDist*j),0)
toCoord = toCoord.Translate(vec)
solids.append(solid.Transform(fromCoord,toCoord))
OUT = solids
The Python node can be found under Core>Scripting in the library. Double clicking
the node opens the python script editor (you can also right click on the node and select Edit...).
You’ll notice some boilerplate text at the top, which is meant to help you reference the
libraries you’ll need. Inputs are stored in the IN array. Values are returned to Dynamo by
assigning them to the OUT variable.
The Autodesk.DesignScript.Geometry library allows you to use dot notation similar to Code
Blocks. For more information on Dynamo syntax, refer to chapter 7.2 as well as the
DesignScript Guide. Typing a geometry type such as 'Point.' will bring up a list of methods for
creating and querying points.
Methods include constructors such as ByCoordinates, actions like Add, and queries like X,
Y and Z coordinates.
Exercise
Download the example fle that accompanies this exercise (Right click and "Save Link
As..."). A full list of example fles can be found in the Appendix. Python_Custom-Node.dyn
In this example, we will write a python script that creates patterns from a solid module, and turn
it into a custom node.
Now that we have our top and bottom surfaces, let’s loft between the two profles to create the
sides of the solid.
1. List.Create: Connect the bottom rectangle and the top polygon to the index inputs.
2. Surface.ByLoft: Loft the two profles to create the sides of the solid.
3. List.Create: Connect the top, side, and bottom surfaces to the index inputs to create a
list of surfaces.
4. Solid.ByJoinedSurfaces: Join the surfaces to create the solid module.
Now that we have our solid, let’s drop a Python Script node onto the workspace.
To add additional inputs to the node, close the editor and click the + icon on the node. The
inputs are named IN[0], IN[1], etc. to indicate that they represent items in a list.
Let’s start by defning our inputs and output. Double click the node to open the python editor.
This code will make more sense as we progress in the exercise. Next we need to think about
what information is required in order to array our solid module. First, we will need to know the
dimensions of the solid to determine the translation distance. Due to a bounding box bug, we
will have to use the edge curve geometry to create a bounding box.
A look at the Python node in Dynamo. Notice that we're using the same syntax as we see
in the titles of the nodes in Dynamo. The commented code is below.
Since we will be both translating and rotating the solid modules, let’s use the
Geometry.Transform operation. By looking at the Geometry.Transform node, we know that we
will need a source coordinate system and a target coordinate system to transform the solid.
The source is the context coordinate system of our solid, while the target will be a different
coordinate system for each arrayed module. That means we will have to loop through the x
and y values to transform the coordinate system differently each time.
A look at the Python node in Dynamo. The commented code is below.
Try changing the seed value to create different patterns. You can also change the
parameters of the solid module itself for different effects. In Dynamo 2.0 you can simply
change the seed and click run without closing the Python window.
Now that we have created a useful python script, let’s save it as a custom node. Select the
python script node, right-click and select ‘New Node From Selection.’
Assign a name, description, and category.
This will open a new workspace in which to edit the custom node.
1. Inputs: Change the input names to be more descriptive and add data types and
default values.
2. Output: Change the output name
Python and Revit
Now that we've demonstrated how to use Python scripts in Dynamo, let's take a look at
connecting Revit libraries into the scripting environment. Remember, we imported our Dynamo
core nodes with the frst three lines in the block of code below. To import the Revit nodes,
Revit elements, and the Revit document manager, we only have to add a few more lines:
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
# Import DocumentManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
import System
This gives us access to the Revit API and offers custom scripting for any Revit task. By
combining the process of visual programming with Revit API scripting, collaboration and tool
development improve signifcantly. For example, a BIM manager and a schematic designer
can work together on the same graph. In this collaboration, they can improve design and
execution of the model.
The examples below demonstrate ways to implement Revit-specifc operations from Dynamo
using Python. For a more detailed review on Python's relationship to Dynamo and Revit, refer
to the Dynamo Wiki page. Another useful resource for Python and Revit is the Revit Python
Shell Project.
Exercise 01
Create a new Revit Project. Download the example fle that accompanies this exercise
(Right click and "Save Link As..."). A full list of example fles can be found in the Appendix.
Revit-Doc.dyn
In these exercises, we'll explore elementary Python scripts in Dynamo for Revit. The exercise
will focus on dealing with Revit fles and elements, as well as the communication between
Revit and Dynamo.
This is a cut and dry method for retrieving the doc, uiapp, and app of the Revit fle linked
to your Dynamo sesson. Programmers who have worked in the Revit API before may
notice the items in the watch list. If these items do not look familiar, that's okay; we'll be
using other examples in the exercises below.
Here is how we're importing Revit Services and retrieving the document data in Dynamo:
A look at the Python node in Dynamo. The commented code is below.
In this exercise, we'll make a simple Model Curve in Revit using the Dynamo Python node.
Begin with the set of nodes in the image above. We'll frst create two reference points in
Revit from Dynamo nodes.
Begin by creating a new Conceptual Mass family in Revit. Launch Dynamo and create the
set of nodes in the image above. We'll frst create two reference point in Revit from
Dynamo nodes.
1. System.Array: Revit needs a System Array as an input (rather than a Python list).
This is just one more line of code, but paying attention to argument types will facilitate
Python programming in Revit.
import clr
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
# Import Revit elements
from Revit.Elements import *
import System
#defne inputs
startRefPt = IN[0]
endRefPt = IN[1]
#defne system array to match with required inputs
refPtArray = System.Array[ReferencePoint]([startRefPt, endRefPt])
#create curve by reference points in Revit
OUT = CurveByPoints.ByReferencePoints(refPtArray)
From Dynamo, we've created two reference points with a line connecting them using
Python. Let's take this a little further in the next exercise.
Exercise 03
Download and unzip the example fles that accompany this exercise (Right click and
"Save Link As..."). A full list of example fles can be found in the Appendix. Revit-
StructuralFraming.zip
This exercise keeps it simple, but drives home the topics of connecting data and geometry
from Revit to Dynamo and back. Let's begin by opening Revit-StructuralFraming.rvt. Once
opened, load Dynamo and open the fle Revit-StructuralFraming.dyn.
This Revit fle is about as basic as it gets. Two reference curves: one drawn on Level 1
and the other drawn on Level 2. We want to get these curves into Dynamo and maintain a
live link.
In this fle we have a set of nodes plugging into fve inputs of a Python node.
1. Select Model Element Nodes: Hit the select button for each and select a
corresponding curve in Revit.
2. Code Block: using the syntax "0..1..#x;", connect an integer slider ranging from 0 to
20 into the x input. This designates the number of beams to draw between the two
curves.
3. Structural Framing Types: We'll choose the default W12x26 beam here from the
dropdown menu.
4. Levels: select "Level 1".
This code in Python is a little more dense, but the comments within the code describe
what's happening in the process:
import clr
#import Dynamo Geometry
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
# Import Revit elements
from Revit.Elements import *
import System
In Dynamo, we can see the results as well. The beams in the Watch3D node refer to the
geometry queried from the Revit elements.
Notice that we have a continuous process of translating data from the Revit Environment to the
Dynamo Environment. In summary, here's how the process plays out:
This may sound a little heavy handed, but the script makes it as simple as editing the curve in
Revit and re-running the solver (although you may have to delete the previous beams when
doing so). This is due to the fact that we are placing beams in python, thus breaking the
association that OOTB nodes have.
With an update to the reference curves in Revit, we get a new array of beams.
Python Templates
With Dynamo 2.0 we have the ability to specify a default template (.py extension) to use
when opening the python window for the frst time. This has been a long-desired request as
this expedites the usage of Python within Dynamo. Having the ability to use a template allows
us to have default imports ready to go when we want to develop a custom Python script.
The location for this template is in the APPDATA location for your Dynamo install.
<PythonTemplateFilePath>
<string>C:\Users\CURRENTUSER\AppData\Roaming\Dynamo\Dynamo
Core\2.0\PythonTemplate.py</string>
</PythonTemplateFilePath>
Next we need to build a template with the functionality that we want to use built-in. In our case
lets embed the Revit related imports and some of the other typical items when working with
Revit.
You can start a blank notepad document and paste the following code inside:
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
clr.AddReference('System')
from System.Collections.Generic import List
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
TransactionManager.Instance.TransactionTaskDone()
OUT = element
Once that is done, save this fle as PythonTemplate.py in the APPDATA location.
Additional information regarding this great addition (by Radu Gidei) can be found here.
https://github.com/DynamoDS/Dynamo/pull/8122
Packages
Once you have created a few Custom Nodes the very next step is to begin organizing and
publishing them by way of Packages - a convenient way to store and share your nodes with
the Dynamo Community.
Packages
An open-source project such as Dynamo thrives on this type of community involvement. With
dedicated third party developers, Dynamo is able to extend its reach to workfows across a
range of industries. For this reason, the Dynamo team has made concerted efforts to
streamline package development and publishing (which will be discussed in more detail in the
following sections).
Installing a Package
The easiest way to install a package is by using the Packages toolbar in your Dynamo
interface. Let's jump right into it and install one now. In this quick example, we'll install a
popular package for creating quad panels on a grid.
In the search bar, let's search for "quads from rectangular grid". After a few moments, you
should see all of the packages which match this search query. We want to select the frst
package with the matching name.
1. Click on the download arrow to the left of the package name and the package will
install. Done!
1. Notice that we now have another group in our Dynamo library called "buildz". This
name refers to the developer of the package, and the custom node is placed in this
group. We can begin to use this right away.
With a quick code block operation to defne a rectangular grid, we've create a list of
rectangular panels.
Package Folders
The example above focuses on a package with one custom node, but you use the same
process for downloading packages with several custom nodes and supporting data fles. Let's
demonstrate that now with a more comprehensive package: Dynamo Unfold.
As in the example above, begin by selecting Packages>Search for a Package.... This
time, we'll search for "DynamoUnfold", one word, minding the caps. When we see the
packages, download by clicking the arrow to the left of the package name. Dynamo Unfold
will now be installed in your Dynamo Library.
In the Dynamo Library, we have a DynamoUnfold Group with multiple categories and
custom nodes.
Now, let's take a look at the package's fle structure. Select "Packages>Manage
Packages..." in Dynamo. We'll see the window above with the two libraries we've installed.
Click the button on the right of DynamoUnfold and select "Show Root Directory".
This will take us to the package's root directory. Notice that we have 3 folders and a fle.
1. The bin folder houses .dll fles. This Dynamo package was developed using Zero-
Touch, so the custom nodes are held in this folder.
2. The dyf folder houses the custom nodes. This package was not developed using
Dynamo custom nodes, so this folder is empty for this package.
3. The extra folder houses all additional fles, including our example fles.
4. The pkg fle is a basic text fle defning the package settings. We can ignore this for
now.
Opening the "extra" folder, we see a bunch of example fles that were downloaded with
the install. Not all packages have example fles, but this is where you can fnd them if they
are part of a package. Let's open up "SphereUnfold".
After opening the fle and hitting "Run" on the solver, we have an unfolded sphere!
Example fles like these are helpful for learning how to work with a new Dynamo package.
You can also download the package fles from the Dynamo Package Manager, but doing so
directly from Dynamo is a more seamless process.
Package Case Study – Mesh Toolkit
The Dynamo Mesh Toolkit provides tools to import meshes from external fle formats, create a
mesh from Dynamo geometry objects, and manually build meshes by their vertices and
indices. The library also provides tools to modify meshes, repair meshes, or extract horizontal
slices for use in fabrication.
The Dynamo Mesh Toolkit is part of Autodesk's ongoing mesh research, and as such will
continue to grow over the coming years. Expect new methods to appear on the toolkit
frequently, and feel free to reach out to the Dynamo team with comments, bugs, and
suggestions for new features.
Meshes vs. Solids
The exercise below demonstrates some basic mesh operations using the Mesh Toolkit. In the
exercise, we intersect a mesh with a series of planes, which can be computationally expensive
using solids. Unlike a solid, a mesh has a set "resolution" and is not defned mathematically,
but topologically, and we can defne this resolution based on the task at hand. For more details
on mesh to solid relationships, you can reference the Geometry For Computation Design
chapter in this primer. For a more thorough examination of Mesh Toolkit, you can reference the
Dynamo Wiki page. Let's jump into the package in the exercise below.
Exercise
Download and unzip the example fles for this exercise (Right click and "Save Link As...").
A full list of example fles can be found in the Appendix. MeshToolkit.zip
1. File Path: Locate the mesh fle to import (stanford_bunny_tri.obj). Supported fle types
are .mix and .obj
2. Mesh.ImportFile: Connect the fle path to import the mesh
1. Point.ByCoordinates: Construct a point – this will be the center of an arc.
2. Arc.ByCenterPointRadiusAngle: Construct an arc around the point. This curve will be
used to position a series of planes.
You should now see a series of planes oriented along the arc. Next, we will use these planes
to intersect the mesh.
1. Mesh.Intersect: Intersect the planes with the imported mesh, creating a series of
polycurve contours.
2. PolyCurve.Curves: Break the polycurves into their curve fragments.
3. Curve.EndPoint: Extract the end points of each curve.
4. NurbsCurve.ByPoints: Use the points to construct a nurbs curve. Use a Boolean node
set to True to close the curves.
1. Surface.ByPatch: Construct surface patches for each contour to create “slices” of the
mesh.
Developing a Package
Dynamo offers a variety of ways to create a package for your personal use or for sharing with
the Dynamo community. In the case study below, we'll walk through how a package is set up
by deconstructing an existing one. This case study builds on lessons from the previous
chapter, providing a set of custom nodes for mapping geometry, by UV coordinates, from one
Dynamo surface to another.
MapToSurface
We're going to work with a sample package which demonstrates the UV mapping of points
from one surface to another. We've already built the fundamentals of the tool in the Creating a
Custom Node section of this primer. The fles below demonstrate how we can take the concept
of UV Mapping and develop a set of tools for a publishable library.
In this image, we map a point from one surface to another using UV coordinates. The
package is based on this concept, but with more complex geometry.
1. When the package is found, click on the big download arrow to the left of the package
name. This will install the package into Dynamo.
1. After installing, the custom nodes should be available under the "DynamoPrimer"
group or your Dynamo Library. With the package now installed, let's walk through
how it's set up.
Custom Nodes
The package we're creating uses fve custom nodes that we've built for reference. Let's walk
through what each node does below. Some custom nodes build off of other custom nodes, and
the graphs have a layout for other users to understand in a straightforward manner.
This is a simple package with fve custom nodes. In the steps below, we'll briefy talk
about each custom node's setup.
PointsToSurface: This is a basic custom node, and one from which all of the other
mapping nodes are based. Simply put, the node maps a point from a source surface UV
coordinate to the location of the target surface UV coordinate. And since points are the
most primitive geometry, from which more complex geometry is built, we can use this logic
to map 2D, and even 3D geometry from one surface to another.
OffsetPointsToSurface: This node gets a little more complex, but the concept is simple:
like the "PointsToSurface" node, this node maps points from one surface to another.
However, it also considers points which are not on the original source surface, gets their
distance to the closest UV parameter, and maps this distance to the target surface normal
at the corresponding UV coordinate. This will make more sense when looking at the
example fles.
SampleSrf: This is a simple node which creates a parametric surface to map from the
source grid to an undulating surface in the example fles.
Example Files
The example fles can be found in the package's root folder (In Dynamo, navigate to this folder
by going to Packages>Manage Packages...).
In the manage packages window, click on the three vertical dots to the right of
"MapToSurface" and choose "Show Root Directory".
With the root directory open, navigate to the "extra" folder, which houses all of the fles in the
package which are not custom nodes. This is where examples fles (if they exist) are stored for
Dynamo packages. The screenshots below discuss the concepts demonstrated in each
example fle.
01-PanelingWithPolygons: This example fle demonstrates how "PointsToSurface" may be
used to panelize a surface based on a grid of rectangles. This should look familiar, as we
demonstrated a similar workfow in the previous chapter.
02-PanelingWithPolygons-II: Using a similar workfow, this exercise fle shows a setup for
mapping circles (or polygons representing circles) from one surface to another. This uses
the "PolygonsToSurface" node.
03-NurbsCrvsAndSurface: This example fle adds some complexity by working with the
"NurbsCrvToSurface" node. The target surface is offset a given distance and the nurbs
curve is mapped to the original target surface and the offset surface. From there, the two
mapped curves are lofted to create a surface, which is then thickened. This resulting solid
has an undulation that is representative of the target surface normals.
04-PleatedPolysurface-OffsetPoints: This example fle demonstrates how to map a
pleated polysurface from a source surface to a target surface. The source and target
surface are a rectangular surface spanning the grid and a revolved surface, respectively.
Publishing a Package
In the previous sections, we dove into the details of how our MapToSurface package is set up
with custom nodes and example fles. But how do we publish a package that has been
developed locally? This case study demonstrates how to publish a package from a set of fles
in a local folder.
There are many ways to publish a package. Below is the process that we advise: publish
locally, develop locally, and then publish online . We'll start with a folder containing all of the
fles in the package.
Uninstalling a Package
Before we jump into publishing the MapToSurface package, if you installed the package from
the previous lesson, uninstall it so that you're not working with identical packages.
Select the button corresponding to "MapToSurface" and select "Uninstall...". Then restart
Dynamo. When reopening, when you check the "Manage Packages" window, the
MapToSurface should no longer be there. Now we're ready to start from the beginning!
Publishing a Package Locally
Note: As of writing this, Dynamo package publication is only enabled in Dynamo Studio or
Dynamo for Revit. Dynamo Sandbox does not have publishing functionality.
Download and unzip the example fles that accompany this package case study (Right
click and "Save Link As..."). A full list of example fles can be found in the Appendix.
MapToSurface.zip
This is the frst submission for our package, and we've placed all of the example fles and
custom nodes into one folder. With this folder prepared, we're ready to upload to the
Dynamo Package Manager.
1. By clicking "Add File", we've also added the fles from the folder structure on the right
side of the screen (to add fles which are not .dyf fles, be sure to change your fle
type in the browser window to "All Files(.)". Notice that we've added every fle, custom
node (.dyf) or example fle (.dyn), indiscriminately. Dynamo will categories these
items when we publish the package.
2. The "Group" feld defnes which group to fnd the custom nodes in the Dynamo UI.
3. Publish by clicking "Publish Locally". If you're following along, be certain to click
"Publish Locally" and not "Publish Online"; we don't want a bunch of duplicate
packages on the Package Manager.
1. After publishing, the custom nodes should be available under the "DynamoPrimer"
group or your Dynamo Library.
Now let's look at the root directory to see how Dynamo has formatted the package we just
created. Do this by clicking Packages>Manage Packages...
In the manage packages window, click on the three vertical dots to the right of
"MapToSurface" and choose "Show Root Directory".
Notice that the root directory is in the local location of your package (remember, we
published the package "locally"). Dynamo is currently referencing this folder to read
custom nodes. It's therefore important to locally publish the directory to a permanent folder
location (ie: not your desktop). Here is the Dynamo package folder breakdown:
1. The bin folder houses .dll fles created with C# or Zero-Touch libraries. We don't have
any for this package so this folder is blank for this example.
2. The dyf folder houses the custom nodes. Opening this will reveal all of the custom
nodes (.dyf fles) for this package.
3. The extra folder houses all additional fles. These fles are likely to be Dynamo Files
(.dyn) or any additional fles required (.svg, .xls, .jpeg, .sat, etc.).
4. The pkg fle is a basic text fle defning the package settings. This is automated in
Dynamo, but can be edited if you want to get into the details.
1. When you're ready to publish, in the "Manage Packages" window, select the button
the right of MapToSurface and choose Publish...
2. If you're updating a package that has already been published, choose "Publish
Version" and Dynamo will update your package online based on the new fles in that
package's root directory. Simple as that!
Publish Version...
When you update the fles in your published package's root folder, you can publish a new
version of the package by selecting "Publish Version..." in the Manage Packages window. This
is a seamless way to make necessary updates to your content and share with the community.
Publish Version will only work if you're the maintainer of the package.
What is Zero-Touch?
With Zero-Touch, you can actually import a library which was not necessarily developed for
Dynamo and create a suite of new nodes. The current Zero-Touch functionality demonstrates
the cross-platform mentality of the Dynamo Project.
This section demonstrates how to use Zero-Touch to import a third party library. For
information on developing your own Zero-Touch Library, reference the Dynamo wiki page.
Zero-Touch Packages
Zero-touch packages are a good complement to user-defned custom nodes. A few packages
which use C# libraries are listed in the table below. For more detailed information on packages,
visit the Packages section in the Appendix.
Logo/Image Name
Mesh Toolkit
Dynamo Unfold
Rhynamo
Optimo
Download and unzip the example fles that accompany this package case study (Right
click and "Save Link As..."). A full list of example fles can be found in the Appendix. Zero-
Touch-Examples.zip .
1. In Dynamo, create a new fle and select File > Import Library...
1. In the pop-up window, navigate to the release folder in your AForge install. This will
likely be in a folder similar to this one: C:\Program Files
(x86)\AForge.NET\Framework\Release.
2. AForge.Imaging.dll: We only want to use this one fle from the AForge library for this
case study. Select this .dll and hit "Open".
1. Back in Dynamo, you should see an "AForge" group of nodes added to your Library
Toolbar. We now have access to the AForge imaging library from our visual program!
Download and unzip the example fles that accompany this package case study (Right
click and "Save Link As..."). A full list of example fles can be found in the Appendix.
ZeroTouchImages.zip
Now that the library's imported, we'll start off simple with this frst exercise (01-
EdgeDetection.dyn). We'll do some basic image processing on a sample image to show how
AForge image flters. We'll use the "Watch Image" node to show our results and apply flters in
Dynamo similar to those in Photoshop
First, we want to import an image to work with. Add a File Path node to the canvas and
select "soapbubbles.jpg" from the downloaded exercise folder (photo cred: fickr).
1. The File Path node simply provides a String of the path to the image we've selected.
We need to convert this File Path to an image in the Dynamo environment.
2. Connect the File Path node to the File.FromPath node.
3. To convert this File into an Image, we'll use the Image.ReadFromFile node.
4. Last, let's see the result! Drop a Watch Image node onto the canvas and connect to
Image.ReadFromFile. We haven't used AForge yet, but we've successfully imported
an image into Dynamo.
Under AForge.Imaging.AForge.Filters (in the navigation menu), you'll notice that there is a
wide array of flters available. We're going to use one of these flters now to desaturate an
image based on threshold values.
1. Drop three sliders onto the canvas, change their ranges to be from 0 to 1 and their
step values to be 0.01.
2. Add the Grayscale.Grayscale node to the canvas. This is an AForge flter which
applies a grayscale flter to an image. Connect the three sliders from step 1 into cr,
cg, and cb. Change the top and bottom sliders to have a value of 1 and the middle
slider to have a value of 0.
3. In order to apply the Grayscale flter, we need an action to perform on our image. For
this, we use IFilter.Apply. Connect the image into the image input and
Grayscale.Grayscale into the iFilter input.
4. Plugging into a Watch Image node, we get a desaturated image.
We can have control over how to desaturate this image based on threshold values for red,
green, and blue. These are defned by the inputs to the Grayscale.Grayscale node. Notice
that the image looks pretty dim - this is because the green value is set to 0 from our slider.
1. Change the top and bottom sliders to have a value of 0 and the middle slider to have
a value of 1. This way we get a more legible desaturated image.
Let's use the desaturated image, and apply another flter on top of it. The desaturated
image has some contrast, so we we're going to test some edge detection.
Now that we're introduced to some basic image processing, let's use an image to drive
Dynamo geometry! On an elementary level, in this exercise we're aiming to do a "Live Trace"
of an image using AForge and Dynamo. We're going to keep it simple and extract rectangles
from a reference image, but there are tools available in AForge for more complex operations.
We'll be working with 02-RectangleCreation.dyn from the downloaded exercise fles.
1. With the File Path node, navigate to grid.jpg in the exercise folder.
2. Connect the remaining series of nodes above to reveal a course parametric grid.
In this next step, we want to reference the white squares in the image and convert them to
actual Dynamo geometry. AForge has a lot of powerful Computer Vision tools, and here we're
going to use a particularly important one for the library called BlobCounter.
1. After adding a BlobCounter to the canvas, we need a way to process the image
(similar to the IFilter tool in the previous exercise). Unfortunately the "Process Image"
node is not immediately visible in the Dynamo library. This is because the function
may not be visible in the AForge source code. In order to fx this, we'll need to fnd a
work-around.
import clr
clr.AddReference('AForge.Imaging')
from AForge.Imaging import *
bc= BlobCounter()
bc.ProcessImage(IN[0])
OUT=bc
Add the code above to the Python node. This code imports the AForge library and then
processes the imported image.
Connecting the image output to the Python node input, we get an
AForge.Imaging.BlobCounter result from the Python node.
The next steps will do some tricks that demonstrate familiarity with the AForge Imaging API. It's
not necessary to learn all of this for Dynamo work. This is more of a demonstration of working
with external libraries within the fexibility of the Dynamo environment.
1. Connect the output of the Python script to BlobCounterBase.GetObjectRectangles.
This reads objects in an image, based on a threshold value, and extracts quantifed
rectangles from the pixel space.
1. Adding another Python node to the canvas, connect to the GetObjectRectangles, and
input the code below. This will create an organized list of Dynamo objects.
OUT = []
for rec in IN[0]:
subOUT=[]
subOUT.append(rec.X)
subOUT.append(rec.Y)
subOUT.append(rec.Width)
subOUT.append(rec.Height)
OUT.append(subOUT)
1. Transpose the output of the Python node from the previous step. This creates 4 lists,
each representing X,Y, Width, and Height for each rectangle.
2. Using Code Block, we organize the data into a structure that accommodates the
Rectangle.ByCornerPoints node (code below).
recData;
x0=List.GetItemAtIndex(recData,0);
y0=List.GetItemAtIndex(recData,1);
width=List.GetItemAtIndex(recData,2);
height=List.GetItemAtIndex(recData,3);
x1=x0+width;
y1=y0+height;
p0=Autodesk.Point.ByCoordinates(x0,y0);
p1=Autodesk.Point.ByCoordinates(x0,y1);
p2=Autodesk.Point.ByCoordinates(x1,y1);
p3=Autodesk.Point.ByCoordinates(x1,y0);
Zooming out, we have an array of rectangles representing the white squares in the image.
Through programming, we've done something (roughly) similar to a live trace in Illustrator!
We still need some cleanup, however. Zooming in, we can see that we have a bunch of
small, unwanted rectangles.
1. We get rid of the unwanted rectangles by inserting a Python node in between the
GetObjectRectangles node and another Python node. The node's code is below, and
removes all rectangles which are below a given size.
rectangles=IN[0]
OUT=[]
for rec in rectangles:
if rec.Width>8 and rec.Height>8:
OUT.append(rec)
With the superfuous rectangles gone, just for kicks, let's create a surface from these
rectangles and extrude them by a distance based on their areas.
1. Last, change the both_sides input to false and we get an extrusion in one direction.
Dip this baby in resin and you've got yourself one super nerdy table.
These are basic examples, but the concepts outlined here are transferable to exciting real-
world applications. Computer vision can be used for a whole host of processes. To name a
few: barcode readers, perspective matching, projection mapping, and augmented reality. For
more advanced topics with AForge related to this exercise, have a read through this article.
LANGUAGES
DesignScript Geometry Basics
The simplest geometrical object in the Dynamo standard geometry library is a point. All
geometry is created using special functions called constructors, which each return a new
instance of that particular geometry type. In Dynamo, constructors begin with the name of the
object’s type, in this case Point, followed by the method of construction. To create a three
dimensional point specifed by x, y, and z Cartesian coordinates, use the ByCoordinates
constructor:
p = Point.ByCoordinates(x, y, z);
Constructors in Dynamo are typically designated with the “By” prefx, and invoking these
functions returns a newly created object of that type. This newly created object is stored in the
variable named on the left side of the equal sign.
Most objects have many different constructors, and we can use the BySphericalCoordinates
constructor to create a point lying on a sphere, specifed by the sphere’s radius, a frst rotation
angle, and a second rotation angle (specifed in degrees):
Points can be used to construct higher dimensional geometry such as lines. We can use the
ByStartPointEndPoint constructor to create a Line object between two points:
// create two points:
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
Similarly, lines can be used to create higher dimensional surface geometry, for instance using
the Loft constructor, which takes a series of lines or curves and interpolates a surface between
them.
// create points:
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
// create lines:
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
l3 = Line.ByStartPointEndPoint(p5, p6);
Surfaces too can be used to create higher dimensional solid geometry, for instance by
thickening the surface by a specifed distance. Many objects have functions attached to them,
called methods, allowing the programmer to perform commands on that particular object.
Methods common to all pieces of geometry include Translate and Rotate, which respectively
translate (move) and rotate the geometry by a specifed amount. Surfaces have a Thicken
method, which take a single input, a number specifying the new thickness of the surface.
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
Intersection commands can extract lower dimensional geometry from higher dimensional
objects. This extracted lower dimensional geometry can form the basis for higher dimensional
geometry, in a cyclic process of geometrical creation, extraction, and recreation. In this
example, we use the generated Solid to create a Surface, and use the Surface to create a
Curve.
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
p = Plane.ByOriginNormal(Point.ByCoordinates(2, 0, 0),
Vector.ByCoordinates(1, 1, 1));
int_surf = solid.Intersect(p);
int_line = int_surf.Intersect(Plane.ByOriginNormal(
Point.ByCoordinates(0, 0, 0),
Vector.ByCoordinates(1, 0, 0)));
Geometric Primitives
While Dynamo is capable of creating a variety of complex geometric forms, simple geometric
primitives form the backbone of any computational design: either directly expressed in the fnal
designed form, or used as scaffolding off of which more complex geometry is generated.
While not strictly a piece of geometry, the CoordinateSystem is an important tool for
constructing geometry. A CoordinateSystem object keeps track of both position and geometric
transformations such as rotation, sheer, and scaling.
// create a CoordinateSystem at x = 0, y = 0, z = 0,
// no rotations, scaling, or sheering transformations
cs = CoordinateSystem.Identity();
CoordinateSystems with geometric transformations are beyond the scope of this chapter,
though another constructor allows you to create a coordinate system at a specifc point,
CoordinateSystem.ByOriginVectors:
cs = CoordinateSystem.ByOriginVectors(origin,
identity.XAxis, identity.YAxis, identity.ZAxis);
phi = 120.3;
The next higher dimensional Dynamo primitive is a line segment, representing an infnite
number of points between two end points. Lines can be created by explicitly stating the two
boundary points with the constructor Line.ByStartPointEndPoint, or by specifying a start point,
direction, and length in that direction, Line.ByStartPointDirectionLength.
p1 = Point.ByCoordinates(-2, -5, -10);
p2 = Point.ByCoordinates(6, 8, 10);
Dynamo has objects representing the most basic types of geometric primitives in three
dimensions: Cuboids, created with Cuboid.ByLengths; Cones, created with
Cone.ByPointsRadius and Cone.ByPointsRadii; Cylinders, created with
Cylinder.ByRadiusHeight; and Spheres, created with Sphere.ByCenterPointRadius.
// create a cuboid with specifed lengths
cs = CoordinateSystem.Identity();
// make a cylinder
cylCS = cs.Translate(10, 0, 0);
// make a sphere
centerP = Point.ByCoordinates(-10, -10, 0);
sph = Sphere.ByCenterPointRadius(centerP, 5);
Vector Math
Objects in computational designs are rarely created explicitly in their fnal position and form,
and are most often translated,rotated, and otherwise positioned based off of existing geometry.
Vector math serves as a kind-of geometric scaffolding to give direction and orientation to
geometry, as well as to conceptualize movements through 3D space without visual
representation.
At its most basic, a vector represents a position in 3D space, and is often times thought of as
the endpoint of an arrow from the position (0, 0, 0) to that position. Vectors can be created with
the ByCoordinates constructor, taking the x, y, and z position of the newly created Vector
object. Note that Vector objects are not geometric objects, and don’t appear in the Dynamo
window. However, information about a newly created or modifed vector can be printed in the
console window:
A set of mathematical operations are defned on Vector objects, allowing you to add, subtract,
multiply, and otherwise move objects in 3D space as you would move real numbers in 1D
space on a number line.
Vector addition is defned as the sum of the components of two vectors, and can be thought of
as the resulting vector if the two component vector arrows are placed “tip to tail.” Vector
addition is performed with the Add method, and is represented by the diagram on the left.
a = Vector.ByCoordinates(5, 5, 0);
b = Vector.ByCoordinates(4, 1, 0);
// c has value x = 9, y = 6, z = 0
c = a.Add(b);
Similarly, two Vector objects can be subtracted from each other with the Subtract method.
Vector subtraction can be thought of as the direction from frst vector to the second vector.
a = Vector.ByCoordinates(5, 5, 0);
b = Vector.ByCoordinates(4, 1, 0);
// c has value x = 1, y = 4, z = 0
c = a.Subtract(b);
Vector multiplication can be thought of as moving the endpoint of a vector in its own direction
by a given scale factor.
a = Vector.ByCoordinates(4, 4, 0);
Often it’s desired when scaling a vector to have the resulting vector’s length exactly equal to
the scaled amount. This is easily achieved by frst normalizing a vector, in other words setting
the vector’s length exactly equal to one.
a = Vector.ByCoordinates(1, 2, 3);
a_len = a.Length;
// len is equal to 5
len = c.Length;
c still points in the same direction as a (1, 2, 3), though now it has length exactly equal to 5.
Two additional methods exist in vector math which don’t have clear parallels with 1D math, the
cross product and dot product. The cross product is a means of generating a Vector which is
orthogonal (at 90 degrees to) to two existing Vectors. For example, the cross product of the x
and y axes is the z axis, though the two input Vectors don’t need to be orthogonal to each
other. A cross product vector is calculated with the Cross method.
a = Vector.ByCoordinates(1, 0, 1);
b = Vector.ByCoordinates(0, 1, 1);
An additional, though somewhat more advanced function of vector math is the dot product. The
dot product between two vectors is a real number (not a Vector object) that relates to, but is
not exactly, the angle between two vectors. One useful properties of the dot product is that the
dot product between two vectors will be 0 if and only if they are perpendicular. The dot product
is calculated with the Dot method.
a = Vector.ByCoordinates(1, 2, 1);
b = Vector.ByCoordinates(5, -8, 4);
// d has value -7
d = a.Dot(b);
Curves: Interpolated and Control Points
There are two fundamental ways to create free-form curves in Dynamo: specifying a collection
of Points and having Dynamo interpolate a smooth curve between them, or a more low-level
method by specifying the underlying control points of a curve of a certain degree. Interpolated
curves are useful when a designer knows exactly the form a line should take, or if the design
has specifc constraints for where the curve can and cannot pass through. Curves specifed via
control points are in essence a series of straight line segments which an algorithm smooths
into a fnal curve form. Specifying a curve via control points can be useful for explorations of
curve forms with varying degrees of smoothing, or when a smooth continuity between curve
segments is required.
num_pts = 6;
s = Math.Sin(0..360..#num_pts) * 4;
int_curve = NurbsCurve.ByPoints(pts);
The generated curve intersects each of the input points, beginning and ending at the frst and
last point in the collection, respectively. An optional periodic parameter can be used to create a
periodic curve which is closed. Dynamo will automatically fll in the missing segment, so a
duplicate end point (identical to the start point) isn’t needed.
pts = Point.ByCoordinates(Math.Cos(0..350..#10),
Math.Sin(0..350..#10), 0);
NurbsCurves are generated in much the same way, with input points represent the endpoints
of a straight line segment, and a second parameter specifying the amount and type of
smoothing the curve undergoes, called the degree.* A curve with degree 1 has no smoothing;
it is a polyline.
num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
A curve with degree 2 is smoothed such that the curve intersects and is tangent to the midpoint
of the polyline segments:
num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
Dynamo supports NURBS (Non-uniform rational B-spline) curves up to degree 20, and the
following script illustrates the effect increasing levels of smoothing has on the shape of a curve:
num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
Note that you must have at least one more control point than the degree of the curve.
Another beneft of constructing curves by control vertices is the ability to maintain tangency
between individual curve segments. This is done by extracting the direction between the last
two control points, and continuing this direction with the frst two control points of the following
curve. The following example creates two separate NURBS curves which are nevertheless as
smooth as one curve:
pts_1 = {};
pts_2 = {};
pts_2[0] = pts_1[4];
end_dir = pts_1[4].Subtract(pts_1[3].AsVector());
This is a very simplifed description of NURBS curve geometry, for a more accurate and
detailed discussion see Pottmann, et al, 2007, in the references.
Translation, Rotation, and Other Transformations
Certain geometry objects can be created by explicitly stating x, y, and z coordinates in three-
dimensional space. More often, however, geometry is moved into its fnal position using
geometric transformations on the object itself or on its underlying CoordinateSystem.
// create a point at x = 1, y = 2, z = 3
p = Point.ByCoordinates(1, 2, 3);
cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
10, 10, 10);
new_cs = CoordinateSystem.Identity();
new_cs2 = new_cs.Rotate(Point.ByCoordinates(0, 0),
Vector.ByCoordinates(1,0,0.5), 25);
cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
10, 10, 10);
new_cs = CoordinateSystem.Identity();
new_cs2 = new_cs.Scale(20);
old_cs = CoordinateSystem.Identity();
old_cs = CoordinateSystem.Identity();
cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
5, 5, 5);
Scaling and shearing are comparatively more complex geometric transformations than rotation
and translation, so not every Dynamo object can undergo these transformations. The following
table outlines which Dynamo objects can have non-uniformly scaled CoordinateSystems, and
sheared CoordinateSystems.
NurbsSurface No No
Circle No No
Plane No No
Polygon No No
Solid No No
Surface No No
Text No No
Surfaces: Interpolated, Control Points, Loft,
Revolve
The two-dimensional analog to a NurbsCurve is the NurbsSurface, and like the freeform
NurbsCurve, NurbsSurfaces can be constructed with two basic methods: inputting a set of
base points and having Dynamo interpolate between them, and explicitly specifying the control
points of the surface. Also like freeform curves, interpolated surfaces are useful when a
designer knows precisely the shape a surface needs to take, or if a design requires the surface
to pass through constraint points. On the other hand, Surfaces created by control points can be
more useful for exploratory designs across various smoothing levels.
surf = NurbsSurface.ByPoints(python_points_1);
We can increase the degree of the NurbsSurface to change the resulting surface geometry:
// python_points_1 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
Just as Surfaces can be created by interpolating between a set of input points, they can be
created by interpolating between a set of base curves. This is called lofting. A lofted curve is
created using the Surface.ByLoft constructor, with a collection of input curves as the only
parameter.
// python_points_2, 3, and 4 are generated with
// Python scripts found in Chapter 12, Section 10
c1 = NurbsCurve.ByPoints(python_points_2);
c2 = NurbsCurve.ByPoints(python_points_3);
c3 = NurbsCurve.ByPoints(python_points_4);
Surfaces of revolution are an additional type of surface created by sweeping a base curve
around a central axis. If interpolated surfaces are the two-dimensional analog to interpolated
curves, then surfaces of revolution are the two-dimensional analog to circles and arcs.
Surfaces of revolution are specifed by a base curve, representing the “edge” of the surface; an
axis origin, the base point of the surface; an axis direction, the central “core” direction; a sweep
start angle; and a sweep end angle. These are used as the input to the Surface.Revolve
constructor.
pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(3, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(5, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
pts[7] = Point.ByCoordinates(4, 0, 7);
crv = NurbsCurve.ByPoints(pts);
All of the points on a curve can be thought of as having a unique parameter ranging from 0 to
1. If we were to create a NurbsCurve based off of several control or interpolated points, the frst
point would have the parameter 0, and the last point would have the parameter 1. It’s
impossible to know in advance what the exact parameter is any intermediate point is, which
may sound like a severe limitation though is mitigated by a series of utility functions. Surfaces
have a similar parameterization as curves, though with two parameters instead of one, called u
and v. If we were to create a surface with the following points:
Parameterization isn’t particularly useful when determining points used to generate curves, its
main use is to determine the locations if intermediate points generated by NurbsCurve and
NurbsSurface constructors.
Curves have a method PointAtParameter, which takes a single double argument between 0
and 1, and returns the Point object at that parameter. For instance, this script fnds the Points
at parameters 0, .1, .2, .3, .4, .5, .6, .7, .8, .9, and 1:
pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(6, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(3, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
crv = NurbsCurve.ByPoints(pts);
pts_at_param = crv.PointAtParameter(0..1..#11);
Similarly, Surfaces have a method PointAtParameter which takes two arguments, the u and v
parameter of the generated Point.
While extracting individual points on a curve and surface can be useful, scripts often require
knowing the particular geometric characteristics at a parameter, such as what direction the
Curve or Surface is facing. The method CoordinateSystemAtParameter fnds not only the
position but an oriented CoordinateSystem at the parameter of a Curve or Surface. For
instance, the following script extracts oriented CoordinateSystems along a revolved Surface,
and uses the orientation of the CoordinateSystems to generate lines which are sticking off
normal to the surface:
pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(3, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(5, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
pts[7] = Point.ByCoordinates(4, 0, 7);
crv = NurbsCurve.ByPoints(pts);
cs_array = surf.CoordinateSystemAtParameter(
(0..1..#7)<1>, (0..1..#7)<2>);
return = Line.ByStartPointEndPoint(lines_start,
lines_end);
}
lines = make_line(Flatten(cs_array));
As mentioned earlier, parameterization is not always uniform across the length of a Curve or a
Surface, meaning that the parameter 0.5 doesn’t always correspond to the midpoint, and 0.25
doesn’t always correspond to the point one quarter along a curve or surface. To get around
this limitation, Curves have an additional set of parameterization commands which allow you to
fnd a point at specifc lengths along a Curve.
Intersection and Trim
Many of the examples so far have focused on the construction of higher dimensional geometry
from lower dimensional objects. Intersection methods allow this higher dimensional geometry
to generate lower dimensional objects, while the trim and select trim commands allow script to
heavily modify geometric forms after they’ve been created.
The Intersect method is defned on all pieces of geometry in Dynamo, meaning that in theory
any piece of geometry can be intersected with any other piece of geometry. Naturally some
intersections are meaningless, such as intersections involving Points, as the resulting object
will always be the input Point itself. The other possible combinations of intersections between
objects are outlined in the following chart. The following chart outlines the result of various
intersection operations:
Intersect
The following very simple example demonstrates the intersection of a plane with a
NurbsSurface. The intersection generates a NurbsCurve array, which can be used like any
other NurbsCurve.
// python_points_5 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
WCS = CoordinateSystem.Identity();
pl = Plane.ByOriginNormal(WCS.Origin.Translate(0, 0,
0.5), WCS.ZAxis);
The Trim method is very similar to the Intersect method, in that it is defned for almost every
piece of geometry. However, there are far more limitations on Trim than on Intersect.
Trim
Using: Point Curve Plane Surface Solid
Polygon - No Yes No No
Something to note about Trim methods is the requirement of a “select” point, a point which
determines which geometry to discard, and which pieces to keep. Dynamo fnds and discards
the trimmed geometry closest to the select point.
tool_pts = Point.ByCoordinates((-10..20..10)<1>,
(-10..20..10)<2>, 1);
tool = NurbsSurface.ByPoints(tool_pts);
pick_point = Point.ByCoordinates(8, 1, 3);
Geometric Booleans
Intersect, Trim, and SelectTrim are primarily used on lower-dimensional geometry such as
Points, Curves, and Surfaces. Solid geometry on the other hand, has an additional set of
methods for modifying form after their construction, both by subtracting material in a manner
similar to Trim and combining elements together to form a larger whole.
The Union method takes two solid objects and creates a single solid object out of the space
covered by both objects. The overlapping space between objects is combined into the fnal
form. This example combines a Sphere and a Cuboid into a single solid Sphere-Cube shape:
s1 = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
s2 = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(4, 0,
0), 6);
combined = s1.Union(s2);
The Difference method, like Trim, subtracts away the contents of the input tool solid from the
base solid. In this example we carve out a small indentation out of a sphere:
s = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
tool = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(10, 0,
0), 6);
result = s.Difference(tool);
The Intersect method returns the overlapping Solid between two solid Inputs. In the following
example, Difference has been changed to Intersect, and the resulting Solid is the missing void
initially carved out:
s = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
tool = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(10, 0,
0), 6);
result = s.Intersect(tool);
Python Point Generators
The following Python scripts generate point arrays for several examples. They should be
pasted into a Python Script node as follows:
python_points_1
out_points = []
for i in range(11):
sub_points = []
for j in range(11):
z = 0
if (i == 5 and j == 5):
z = 1
elif (i == 8 and j == 2):
z = 1
sub_points.Add(Point.ByCoordinates(i, j, z))
out_points.Add(sub_points)
OUT = out_points
python_points_2
out_points = []
for i in range(11):
z = 0
if (i == 2):
z = 1
out_points.Add(Point.ByCoordinates(i, 0, z))
OUT = out_points
python_points_3
out_points = []
for i in range(11):
z = 0
if (i == 7):
z = -1
out_points.Add(Point.ByCoordinates(i, 5, z))
OUT = out_points
python_points_4
out_points = []
for i in range(11):
z = 0
if (i == 5):
z = 1
out_points.Add(Point.ByCoordinates(i, 10, z))
OUT = out_points
python_points_5
out_points = []
for i in range(11):
sub_points = []
for j in range(11):
z = 0
if (i == 1 and j == 1):
z = 2
elif (i == 8 and j == 1):
z = 2
elif (i == 2 and j == 6):
z = 2
sub_points.Add(Point.ByCoordinates(i, j, z))
out_points.Add(sub_points)
OUT = out_points
Best Practices
This part of the primer is organized in the spirit of a journal of “best practices”. It sheds light on
several strategies that we have learned, through experience and research, to be most
conducive to quality parametric workfows. As designers and programmers, our metric for
quality is primarily concerned with the maintainability, dependability, usability, and effciency of
our tools. While these best practices have specifc examples for either visual or text based
scripting, the principles are applicable to all programming environments and can inform many
computational workfows.
Graph Strategies
Prior to this chapter, the Primer has covered how to implement the powerful visual-scripting
capabilities of Dynamo. A good understanding of these capabilities is a solid foundation and
the frst step in building robust visual programs. When we use our visual programs in the feld,
share them with colleagues, troubleshoot errors, or test limits we have additional issues to deal
with. If someone else will be using your program or you are expecting to open it six months
from now, it needs to have an immediate graphic and logical clarity. Dynamo has many tools to
manage the complexity of your program, and this chapter will give guidelines on when to use
them.
Reduce Complexity
As you develop your Dynamo graph and test ideas, it can quickly grow in size and complexity.
While it is important that you create a functioning program, it is equally important to do it as
simply as possible. Not only will your graph run faster and more predictably, you along with
other users will understand its logic later on. The following are several ways that will help you
clarify the logic of your graph.
Groups allow you to create functionally distinct parts as you build a program
Groups allow you to move large parts of the program around while maintaining modularity
and alignment
You can change the color of the group to differentiate what Groups are doing (inputs vs
functions)
You can use groups to start organizing your graph to streamline Custom Node creation
The colors in this program identify the purpose of each group. This strategy can be used
to create hierarchy in any graphic standards or templates you develop.
At times, you can use a Code Block to type a number or node method faster than
searching (Point.ByCoordinates, Number, String, Formula)
Code Blocks are useful when you want to defne custom functions in DesignScript to
reduce the number of nodes in a graph
Both 1 and 2 perform the same function. It was much faster to write a few lines of code
than it was to search for and add each node individually. The code block is also far more
concise.
You can reduce the complexity of a graph by using Node to Code which will take a
collection of simple nodes and write their corresponding DesignScript in a single Code
Block
Node to Code can condense code without eliminating the program’s clarity
The following are the pros of using Node to Code:
Easily condenses code into one component that is still editable
Can simplify a signifcant portion of the graph
Useful if the ‘mini-program’ will not often be edited
Useful for incorporating other code block functionality, like functions
The following are the cons of using Node to Code:
Generic naming makes it less legible
More diffcult to understand for other users
No easy way to return to the visual programming version
1. Existing program
2. Code Block created from Node to Code
Using List@Level can help you reduce the complexity of your graph by replacing List.Map
and List.Combine nodes which might occupy a considerable amount of canvas space
List@Level provides you with a quicker way than List.Map/List.Combine to construct node
logic by allowing you to access data at any level in a list right from the input port of a node
We can verify how many True values BoundingBox.Contains is returning and in which lists
by activating List@Level for CountTrue's "list" input. List@Level allows the user to
determine at which level the input will take data from. Using List@Level is fexible,
effcient, and highly encouraged over other methods involving List.Map and List.Combine.
Maintain Readability
In addition to making your graph as simple and effcient as possible, strive for graphic clarity.
Despite your best efforts to make your graph intuitive with logical groupings, relationships
might not be readily apparent. A simple Note inside of a Group or renaming a slider can save
you or another user from unnecessary confusion or panning across the graph. The following
are several ways that will help you apply graphic consistency within and across your graphs.
1. Unorganized graph
2. Aligned graph
Renaming inputs can help others easily understand your graph, especially if what they
plug into will be off the screen
Be wary of renaming nodes other than inputs. An alternative to this is creating a custom
node from a node cluster and renaming that; it will be understood that it contains
something else
1. Inputs for surface manipulation
2. Inputs for architectural parameters
3. Inputs for drainage simulation script
To rename a node, right click on its name and choose "Rename Node...".
You should add a Note if something in the graph requires a plain language explanation
that the nodes can not express
You should add a Note if a collection of nodes or a Group is too large or complex and
can’t be easily understood right away
1. A Note describing the portion of the program that returns raw translation distances
2. A Note describing the code that maps those values to a Sine wave
For how to add a Note, refer to Managing Your Program .
Flex Continuously
While building your visual-script, it is important to verify that what is being returned is what you
expected. Not all errors or issues will cause the program to fail immediately, especially null or
zero values that could affect something far downstream. This strategy is also discussed in the
context of text-scripting in Scripting Strategies. The following practice will help ensure that you
are getting what you expected.
Use Watch or Preview Bubbles as you build the program to verify that key outputs are
returning what you expected
The Watch nodes are being used to compare:
Ensure Reusability
It is highly likely that someone else will be opening your program at some point, even if you are
working independently. They should be able to quickly understand what the program needs
and produces from its inputs and outputs. This is especially important when developing a
Custom Node to be shared with the Dynamo community and used in someone else’s program.
These practices lead to robust, reusable programs and nodes.
Manage the I/O
To ensure legibility and scalability, you should try and minimize inputs and outputs as
much as possible
You should try to strategize how you are going to build the logic by frst creating a rough
outline of how the logic could work before you even add a single node to the canvas. As
you develop the rough outline, you should keep track of which inputs and outputs will go
into scripts
If there are particular options or conditions that you want embedded in the graph, you
should use Presets for quick access
You can also use Presets to reduce complexity by caching specifc slider values in a graph
with long run times
For how to use Presets, refer to Managing Your Data with Presets .
You should use a Custom Node if your program can be collected into a single container
You should use a a Custom Node when a portion of the graph will be reused often in other
programs
You should use a Custom Node if you want to share a functionality with the Dynamo
Community
Collecting the point translation program into a Custom Node makes a robust, unique
program portable and far easier to understand. Well named input ports will help other
users understand how to use the node. Remember to add descriptions and required data
types for each input.
Build templates
You can build templates to establish graphic standards across your visual graphs to
ensure collaborators have a standardized way of understanding graph
When building a template, you can standardize group colors and font sizes to categorize
types of workfows or data actions.
When building a template, you can even standardize how you want to label, color, or style
the difference between front-end and back-end workfows in your graph.
1. The UI, or front-end, of the program includes a project name, input sliders, and import
geometry.
2. The back-end of the program.
3. Group color categories (the general design, inputs, Python scripting, imported
geometry).
Now that we have established several best practices, let’s apply them to a program that was
put together quickly. Though the program succeeds in generating the roof, the state of the
graph is a "mind-map" of the author. It lacks any organization or description of its use. We will
walk through our best practices to organize, describe, and analyze the program so other users
can understand how to use it.
The program is functioning, but the graph is disorganized.
Let's start by determining the data and geometry returned by the program.
Understanding when major changes to the data occur is crucial to establishing logical
divisions, or modularity. Try inspecting the rest of the program with Watch nodes to see if
you can determine groups before moving on to the next step.
1. This Code Block with a math equation looks like a crucial piece of the program. A
Watch node displays that it is returning lists of translation distances.
2. The purpose of this area isn't readily obvious. The arrangement of True values at list
level L2 from BoundingBox.Contains and the presence of List.FilterByBoolMask
suggests we are sampling a portion of the point grid.
Once we understand the elemental parts of the program, let's put them in Groups.
Groups allow the user to visually differentiate the parts of the program.
With Groups established, align the nodes to create visual continuity across the graph.
Visual continuity helps the user to see the program fow and implicit relationships between
nodes.
Make the program more accessible by adding another layer of graphic improvements. Add
notes to describe how a specifc area of the program works, give inputs custom names, and
assign colors to different types of groups.
These graphic improvements tell the user more about what the program is doing. The
different group colors help to distinguish inputs from functions.
1. Notes
2. Inputs with descriptive names
Before we start to condense the program, let's fnd a strategic location to introduce the Python
script drainage simulator. Plug the output of the frst scaled roof surface into the respective
scripting input.
We've chosen to integrate scripting at this point in the program so the drainage simulation
can be run on the original, single roof surface. That specifc surface is not being
previewed, but it saves us from having to choose the top surface of the chamfered
Polysurface.
Scripting Strategies
Text-based scripting within the visual-scripting environment enables powerful and visual
relationships using DesignScript, Python, and ZeroTouch (C#). The user can expose elements
such as input sliders, condense large operations into DesignScript, and access powerful tools
and libraries through Python or C# all within the same workspace. If managed effectively,
combining these strategies can lend a great deal of customization, clarity, and effciency to the
overall program. The following are a set of guidelines to help you augment your visual-script
with text-script.
Looping
Recursion
Choose a language:
Condense Ext.
Looping Recursion Shorthand
Nodes Libraries
ZeroTouch
No No No Yes No
(C#)
Refer to Scripting Reference for a list of what each Dynamo library gives you access to.
Think Parametrically
When scripting in Dynamo, an inevitably parametric environment, it is wise to structure your
code relative to the framework of nodes and wires it will be living in. Consider the node
containing your text-script as though it is any other node in the program with a few specifc
inputs, a function, and an expected output. This immediately gives your code inside the node a
small set of variables from which to work, the key to a clean parametric system. Here are some
guidelines for better integrating code into a visual program.
Constants
Whenever entities in your script are logically related, aim to defne them as functions of
each other. This way when one is modifed, the other can update proportionally.
If a set of parameters can be derived from more parent parameters, only expose the
parent parameters as script inputs. This increases the usability of your script by
reducing the complexity of its interface.
The code "modules" from the example in Python Node.
1. Inputs.
2. Variables internal to the script.
3. A loop that uses these inputs and variables to perform its function.
When you have multiple ways to express the same thing in your script, at some point the
duplicate representations will fall out of sync which can lead to maintenance nightmares,
poor factoring, and internal contradictions.
The DRY principle is stated as "Every piece of knowledge must have a single,
unambiguous, authoritative representation within a system":
When this principle is successfully applied, all the related elements in your script
change predictably and uniformly and all the unrelated elements do not have logical
consequences on each other.
### BAD
for i in range(4):
for j in range(4):
point = Point.ByCoordinates(3*i, 3*j, 0)
points.append(point)
### GOOD
count = IN[0]
pDist = IN[1]
for i in range(count):
for j in range(count):
point = Point.ByCoordinates(pDist*i, pDist*j, 0)
points.append(point)
Tip: Before duplicating entities in your script (such as constant in the example above), ask
yourself if you can link to the source instead.
Structure Modularly
As your code gets longer and more complex the “big idea”, or overarching algorithm becomes
increasingly illegible. It also becomes more diffcult to keep track of what (and where) specifc
things happen, fnd bugs when things go wrong, integrate other code, and assign development
tasks. To avoid these headaches it’s wise to write code in modules, an organizational strategy
that breaks up code based on the task it executes. Here are some tips for making your scripts
more manageable by way of modularization.
A "module" is a group of code that performs a specifc task, similar to a Dynamo Node in
the workspace.
This can be anything that should be visually separated from adjacent code (a function, a
class, a group of inputs, or the libraries you are importing).
Developing code in modules harnesses the visual, intuitive quality of Nodes as well as the
complex relationships that only text-scripting can achieve.
These loops call a class named "agent" that we will develop in the exercise.
If you fnd that your code does the same (or very similar) thing in more than once place,
fnd ways to cluster it into a function that can be called.
"Manager" functions control program fow and primarily contain calls to "Worker" functions
that handle low-level details, like moving data between structures.
This example creates spheres with radii and color based on the Z value of the center
points.
1. Two "worker" parent functions: one that creates spheres with radii and display colors
based the centerpoint's Z value.
2. A "manager" parent function that combines the two worker functions. Calling this will
call both functions inside it.
A module interface expresses the elements that are provided and required by the module.
Once the interfaces between the units have been defned, the detailed design of each unit
can proceed separately.
Separability/Replaceability:
Code Grouping:
# IMPORT LIBRARIES
import random
import math
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
Functions:
def get_step_size():
area = surfIn.Area
stepSize = math.sqrt(area)/100
return stepSize
stepSize = get_step_size()
Classes:
class MyClass:
i = 12345
def f(self):
return 'hello world'
numbers = MyClass.i
greeting = MyClass.f
Flex Continuously
While developing text-scripts in Dynamo, it is wise to constantly make sure that what is actually
being created is in line with what you are expecting. This will ensure that unforeseen events--
syntax errors, logical discrepancies, value inaccuracies, anomalous outputs etc.-- are quickly
discovered and dealt with as they surface rather than all at once at the end. Because text-
scripts live inside nodes on the canvas, they are already integrated into the data fow of your
visual program. This makes the successive monitoring of your script as simple as assigning
data to be outputted, running the program, and evaluating what fows out of the script using a
Watch Node. Here are some tips for continuously inspecting your scripts as you construct
them.
Assign the most recent data you are working with in your script as the output so that the
node is always outputting relevant data when the script updates:
Flexing the example code from Python Node.
1. Check that all edges of the solid are being returned as curves to create a bounding
box around.
2. Check that our Count inputs are successfully being converted to Ranges.
3. Check that coordinate systems have been properly translated and rotated in this loop.
While scripting, crank your input parameters to the minimum and maximum values of their
allotted domain to check if the program still functions under extreme conditions.
Sometimes bugs and errors that reveal some underlying problem with your script will only
surface during these edge cases.
Understand what is causing the error and then decide if it needs to be fxed internally
or if a parameter domain needs to be redefned to avoid the problem.
Tip: Always assume the that the user will use every combination of every input value that
has been exposed to him/her. This will help eliminate unwanted surprises.
Debug Effciently
Debugging is the process of eliminating "bugs" from your script. Bugs can be errors,
ineffciencies, inaccuracies, or any unintended results. Addressing a bug can be as simple as
correcting a misspelled variable name to more pervasive, structural problems with your script.
Ideally, fexing your script as you build it will help to catch these potential issues early, though
this is no guarantee of it being bug-free. The following is a review of several best practices
from above to help you address bugs systematically.
Check the data returned at different places in the code by assigning it to the OUT variable,
similar to the concept of fexing the program.
A module of code will be much easier to debug if its intended outcome is clearly
described.
# Transform the solid from the source coord system to the target coord system and
append to the list
solids.append(solid.Transform(fromCoord,toCoord))
Normally this would be an excessive amount of commenting and blank lines, but when
debugging it can be useful to break things down into manageable pieces.
Once the faulty module has been identifed, fxing the problem is considerably simpler.
When a program must be modifed, code that has been developed in modules will be
much easier to change:
You can insert new or debugged modules into an existing program with the
confdence that the rest of the program will not change.
1. The input geometry is returning a bounding box larger that itself, as we can see from
assigning xDist and yDist to OUT.
2. The edge curves of the input geometry return an appropriate bounding box with
correct distances for xDist and yDist.
3. The code "module" we've inserted to address the xDist and yDist value issue.
With our best practices for text-scripting in mind, let's write a rain simulation script. While we
were able to apply best practices to a disorganized visual program in Graph Strategies, it is far
more diffcult to do that with text-scripting. Logical relationships established in text-scripting are
less visible and can be almost impossible to untangle in messy code. With the power of text-
scripting comes a larger responsibility in organization. We will walk through each step and
apply best practices along the way.
The frst thing we need to do is import the necessary Dynamo libraries. Doing this frst will give
global access to Dynamo functionality in Python.
Next we need to defne the script's inputs and output, which will display as input ports on the
node. These external inputs are the foundation for our script and the key to establishing a
parametric environment.
We need to defne inputs that correspond to variables in the Python script and determine
a desired output:
Now let's employ the practice of modularity and create the body of our script. Simulating the
shortest path down a surface for multiple start points is a signifcant task that will require
several functions. Rather than call the different functions throughout the script, we can
modularize our code by collecting them into a single class, our agent. The different functions of
this class or "module" can be called with different variables or even reused in another script.
We will need to defne a class, or blueprint, for an agent with the intention of walking down
a surface by choosing to travel in the steepest possible direction each time it takes a step:
1. Name.
2. Global attributes that all the agents share.
3. Instance attributes that are unique to each agent.
4. A function for taking a step.
5. A function for cataloging the position of each step to a trail list.
Let's initialize the agents by defning their start location. This is a good opportunity to fex our
script and make sure the agent class is working.
We will need to instantiate all the agents we want to observe walk down the surface and
defne their initial attributes:
We will then need to enter a nested loop where for each agent and for each step, we
update and record their position into their trail list. At each step we will also make sure the
agent hasn’t reached a point on the surface where it cannot take another step which will
allow it to descend. If that condition is met, we will end that agent's trip.
Now that our agents have been fully updated, let's return geometry that represents them.
After all the agents have either reached their limit of descent or their maximum number of
steps we will create a polycurve through the points in their trail list and output the
polycurve trails.
Scripting Reference
This reference page extends the best practices covered in Scripting Strategies with greater
detail on code libraries, labeling, and styling. We will be using Python to illustrate the concepts
below, but the same principles would apply in Python and C#(Zerotouch) but in different
syntax.
Standard libraries from Python and C# can be used to build advanced data and fow
structures in the Dynamo environment.
Dynamo libraries directly correspond to the node hierarchy for creating geometry and
other Dynamo objects.
Dynamo Libraries
ProtoGeometry
Functionality: Arc, Bounding Box, Circle, Cone, Coordinate System, Cuboid, Curve,
Cylinder, Edge, Ellipse, Ellipse Arc ,Face, Geometry, Helix, Index Group, Line, Mesh,
Nurbs Curve, Nurbs Surface, Plane, Point, Polygon, Rectangle, Solid, Sphere,
Surface, Topology, TSpline, UV, Vector, Vertex.
How to import: import Autodesk.DesignScript.Geometry
Note when using ProtoGeometry through Python or C#, you are creating unmanaged
objects, which need have their memory managed manually - please see section
below: Unmanaged Objects, for more info.
DSCoreNodes
Functionality: Color, Color Range 2D, Date Time, Time Span, IO, Formula, Logic, List,
Math, Quadtree, String, Thread.
How to import: import DSCore
Tessellation
Functionality: Convex Hull, Delaunay, Voronoi.
How to import: import Tessellation
DSOffce
Functionality: Excel.
How to import: import DSOffce
Label Carefully
While scripting, we are constantly using identifers to denote things like variables, types,
functions, and other entities. Through this system of symbolic notation, while building
algorithms we can conveniently refer to information by way of labels --usually made up of a
sequence of characters. Naming things well plays a signifcant role in writing code that can be
easily read and understood by others as well as your future self! Here are some tips to keep in
mind while naming things in your script:
### BAD
csfX = 1.6
csfY= 1.3
csfZ = 1.0
### GOOD
# column scale factor (csf)
csfX = 1.6
csfY= 1.3
csfZ = 1.0
Avoid redundant labeling:
### BAD
import car
seat = car.CarSeat()
tire = car.CarTire()
### GOOD
import car
seat = car.Seat()
tire = car.Tire()
Use positive logic for your variable names instead of negative logic:
### BAD
if 'mystring' not in text:
print 'not found'
else:
print 'found'
print 'processing'
### GOOD
if 'mystring' in text:
print 'found'
print 'processing'
else:
print 'not found'
### BAD
agents = …
active_agents = …
dead_agents ...
### GOOD
agents = …
agents_active = …
agents_dead = ...
Aliases should be used to shorten overly long and often repeated chains:
### BAD
from RevitServices.Persistence import DocumentManager
DocumentManager = DM
doc = DM.Instance.CurrentDBDocument
uiapp = DM.Instance.CurrentUIApplication
### GOOD
from RevitServices.Persistence import DocumentManager as DM
doc = DM.Instance.CurrentDBDocument
uiapp = DM.Instance.CurrentUIApplication
### BAD
rotateToCoord =
rotateFromCoord.Rotate(solid.ContextCoordinateSystem.Origin,Vector.ByCoordinates(0,0,1),5)
### GOOD
toCoord =
fromCoord.Rotate(solid.ContextCoordinateSystem.Origin,Vector.ByCoordinates(0,0,1),5)
“Everything should be made as simple as possible, but not simpler.” – Albert Einstein
Style Consistently
Generally speaking there is more than one way to program just about anything, therefore your
“personal style” of scripting is the result of the countless small decisions you choose to make
(or not make) along the way. That said, the readability and maintainability of your code is a
direct result of its internal consistency as well as its adherence to general stylistic conventions.
As a rule of thumb, code that looks the same in two places should work the same, too. Here
are a few tips for writing clear and consistent code.
Naming conventions: (Choose one of the conventions below for each type of entity in your
code and stick to it!)
Private methods:
__double_leading_underscore(self, ...)
Constants:
ALL_CAPS_WITH_UNDERSCORES
Tip: Avoid one-letter variables (esp. l, O, I) except in very short blocks, when the meaning
is clearly visible from the immediate context.
Surround top-level function and class defnitions with two blank lines.
Extra blank lines may be used (sparingly) to separate groups of related functions.
Avoid extraneous whitespace:
### BAD
function( apples[ 1 ], { oranges: 2 } )
### GOOD:
function(apples[1], {oranges: 2})
### BAD
if x == 2 : print x , y ; x , y = y , x
### GOOD
if x == 2: print x, y; x, y = y, x
Immediately before the open parenthesis that starts the argument list of a function call:
### BAD
function (1)
### GOOD
function(1)
### BAD
dict ['key'] = list [index]
### GOOD
dict['key'] = list[index]
Always surround these binary operators with a single space on either side:
assignment ( = )
augmented assignment ( += , -= etc.)
comparisons ( == , < , > , != , <> , <= , >= , in , not in , is , is not )
Booleans ( and , or , not )
Limiting the required editor window width makes it possible to have several fles open
side-by-side, and works well when using code review tools that present the two versions in
adjacent columns.
Long lines can be broken over multiple lines by wrapping expressions in parentheses:
Sometimes fewer comments makes for more readable code. Especially if it forces you to
use meaningful symbol names instead.
### BAD
# get the country code
country_code = get_country_code(address)
# if country code is US
if (country_code == 'US'):
# display the form input for state
print form_input_state()
### GOOD
# display state selection for US users
country_code = get_country_code(address)
if (country_code == 'US'):
print form_input_state()
Tip: Comments tell you why, Code tells you how.
Open Source projects are built on the collaborative efforts of many developers. These
projects need to maintain a high level of code readability so that the team can work
together as effciently as possible. Therefore, it is a good idea to browse through the
source code of these projects to observe what these developers are doing.
Question whether or not each convention is working for the needs at hand.
C# (Zerotouch) Standards
Check out these wiki pages for guidance on writing C# for Zerotouch and contributing to
Dynamo:
This wiki covers some general coding standards for documenting and testing your code:
https://github.com/DynamoDS/Dynamo/wiki/Coding-Standards
This wiki specifcally covers naming standards for libraries, categories, node names, port
names, and abbreviations: https://github.com/DynamoDS/Dynamo/wiki/Naming-Standards
Unmanaged Objects:
You only need to dispose unmanaged resources that you don't return into the graph or
store a reference to. For the rest of this section, we'll refer to these objects as intermediate
geometry. You can see an example of this class of object in the code example below. This
zero touch C# function singleCube returns a single cube, but creates 10000 extra cubes
during its execution. We can pretend this other geometry was used as some intermediate
construction geometry.
This zero touch function will most likely crash Dynamo. Since we created 10000 solids, but
only stored one of them, and only returned that one. We should instead, dispose all of our
intermediate cubes, except the one that we return. We don't want to dipose what we
return, as it will be propogated into the graph and used by other nodes.
for(int i = 0; i<10000;i++){
output = Cuboid.ByLengths(1,1,1);
}
return output;
}
for(int i = 0; i<10000;i++){
toDispose.Add(Cuboid.ByLengths(1,1,1));
}
return output;
}
In general you only need to dispose geometry like Surfaces , Curves , and Solids . To be
safe though, you can dispose all geometry types ( Vectors , Points , CoordinateSystems ).
Appendix A: Resources
In this section, you can fnd additional resources for taking your Dynamo game one step
further. We've also added an index of important nodes, a collection of useful packages, and a
repository of the example fles in this primer. Please feel free to add to this section...remember,
the Dynamo Primer is open source!
LANGUAGES
Resources
Dynamo Wiki
"This wiki is for learning about development using the Dynamo API, supporting libraries and
tools."
https://github.com/DynamoDS/Dynamo/wiki
Dynamo Blog
This blog is the most up-to-date collection of articles from the Dynamo team, discussing new
features, workfows, and all things Dynamo.
http://dynamobim.com/blog/
DesignScript Guide
Programming languages are created to express ideas, usually involving logic and calculation.
In addition to these objectives, the Dynamo textual language (formerly DesignScript) has been
created to express design intentions. It is generally recognized that computational designing is
exploratory, and Dynamo tries to support this: we hope you fnd the language fexible and fast
enough to take a design from concept, through design iterations, to your fnal form. This
manual is structured to give a user with no knowledge of either programming or architectural
geometry full exposure to a variety of topics in these two intersecting disciplines.
http://dynamobim.org/wp-content/links/DesignScriptGuide.pdf
The Dynamo Primer is an open source project, initiated by Matt Jezyk and the Dynamo
Development team at Autodesk. The frst version of the primer was developed by Mode Lab.
To contribute, fork the repo, add your content, and submit a pull request.
https://github.com/DynamoDS/DynamoPrimer
https://github.com/DynamoDS/Dynamo/wiki/Zero-Touch-Plugin-Development
https://www.python.org/about/gettingstarted
AForge
AForge.NET is an open source C# framework designed for developers and researchers in the
felds of Computer Vision and Artifcial Intelligence - image processing, neural networks,
genetic algorithms, fuzzy logic, machine learning, robotics, etc.
http://www.aforgenet.com/framework/
Wolfram MathWorld
http://mathworld.wolfram.com/
Revit Resources
buildz
"These posts are mainly about the Revit platform, with recommendations on how to enjoy it."
http://buildz.blogspot.com/
"This notebook attempts to remedy a few 'resource defciencies' in learning and applying the
Revit API in the context of a design workfow"
http://wiki.theprovingground.org/revit-api
"The RevitPythonShell adds an IronPython interpreter to Autodesk Revit and Vasari." This
project pre-dates Dynamo and is a great reference for Python development.
RPS Project:
https://github.com/architecture-building-systems/revitpythonshell
Developer's Blog:
http://darenatwork.blogspot.com/
A robust catalogue of Revit API workfows from one of the leading experts in BIM.
http://thebuildingcoder.typepad.com/
INDEX OF NODES
This index provides additional information on all the nodes used in this primer, as well as other
components you might fnd useful. This is just an introduction to some of the 500 nodes available in
Dynamo.
Bulitin Functions
Count
Returns number of items in the specifed list.
Flatten
Returns the fattened 1D list of the multidimensional input list.
Map
Maps a value into an input range
Core
Core.Color
CREATE
Color.ByARGB
Construct a color by alpha, red, green, and blue components.
Color Range
Get a color from a color gradient between a start color and an
end color.
ACTIONS
Color.Brightness
Gets the brightness value for this color.
Color.Components
Lists the components for the color in the order: alpha, red, green,
blue.
Color.Saturation
Gets the saturation value for this color
Color.Hue
Gets the hue value for this color.
QUERY
Color.Alpha
Find the alpha component of a color, 0 to 255.
Color.Blue
Find the blue component of a color, 0 to 255.
Color.Green
Find the green component of a color, 0 to 255.
Color.Red
Find the red component of a color, 0 to 255.
Core.Display
CREATE
Display.ByGeometryColor
Displays geometry using a color.
Core.Input
ACTIONS
Boolean
Selection between a true and false.
Code Block
Allows for DesignScript code to be authored directly.
Directory Path
Allows you to select a directory on the system to get its path
File Path
Allows you to select a fle on the system to get its flename.
Integer Slider
A slider that produces integer values.
Number
Creates a number.
Number Slider
A slider that produces numeric values.
String
Creates a string.
Core.List
CREATE
List.Create
Makes a new list out of the given inputs.
List.Combine
Applies a combinator to each element in two sequences
Number Range
Creates a sequence of numbers in the specifed range.
Number Sequence
Creates a sequence of numbers.
ACTIONS
List.Chop
Chop a list into a set of lists each containing the given amount of
items.
List.Count
Gets the number of items stored in the given list.
List.Flatten
Flattens a nested list of lists by a certain amount.
List.FilterByBoolMask
Filters a sequence by looking up corresponding indices in a
separate list of booleans.
List.GetItemAtIndex
Gets an item from the given list that's located at the specifed
index.
List.Map
Applies a function over all elements of a list, generating a new list
from the results
List.Reverse
Creates a new list containing the items of the given list but in
reverse order
List.ReplaceItemAtIndex
Replace an item from the given list that's located at the specifed
index
List.ShiftIndices
Shifts indices in the list to the right by the given amount
List.TakeEveryNthItem
Fetches items from the given list at indices that are multiples of
the given value, after the given offset.
List.Transpose
Swaps rows and columns in a list of lists. If there are some rows
that are shorter than others, null values are inserted as place
holders in the resultant array such that it is always rectangular
Core.Logic
ACTIONS
If
Conditional statement. Checks the boolean value of the test
input. If the test input is true, the result outputs the true input,
otherwise the result outputs the false input.
Core.Math
ACTIONS
Math.Cos
Fines the cosine of an angle.
Math.DegreesToRadians
Converts an angle in degrees to an angle in radians.
Math.Pow
Raises a number to the specifed power.
Math.RadiansToDegrees
Converts an angle in radians to an angle in degrees.
Math.RemapRange
Adjusts the range of a list of numbers while preserving the
distribution ratio.
Math.Sin
Finds the sine of an angle.
Core.Object
ACTIONS
Object.IsNull
Determines if the given object is null.
Core.Scripting
ACTIONS
Formula
Evaluates mathematical formulas. Uses NCalc for evaluation. See
http://ncalc.codeplex.com
Core.String
ACTIONS
String.Concat
Concatenates multiple strings into a single string.
String.Contains
Determines if the given string contains the given substring.
String.Join
Concatenates multiple strings into a single string, inserting the
given separator between each joined string.
String.Split
Divides a single string into a list of strings, with divisions
determined by the given separater strings.
String.ToNumber
Converts a string to an integer or a double.
Core.View
ACTIONS
View.Watch
Visualize the output of node.
View.Watch 3D
Shows a dynamic preview of geometry.
Geometry
Geometry.Circle
CREATE
Circle.ByCenterPointRadius
Creates a Circle with input center Point and radius in the world XY
plane, with world Z as normal.
Circle.ByPlaneRadius
Create a Circle centered at the input Plane origin (root), lying in
the input Plane, with given radius.
Geometry.CoordinateSystem
CREATE
CoordinateSystem.ByOrigin
Create a CoordinateSystem with origin at input Point, with X and Y
Axes set as WCS X and Y axes
CoordinateSystem.ByCyclindricalCoordinates
Creates a CoordinateSystem at the specifed cylindrical coordinate
parameters with respet to the specifed coordinate system
Geometry.Cuboid
CREATE
Cuboid.ByLengths (origin)
Create a Cuboid centered at input Point, with specifed width,
length, and height.
Geometry.Curve
ACTIONS
Curve.Extrude (distance)
Extrudes a Curve in the normal Vector direction.
Curve.PointAtParameter
Get a Point on the Curve at a specifed parameter between
StartParameter() and EndParameter().
Geometry.Geometry
ACTIONS
Geometry.DistanceTo
Obtain the distance from this Geometry to another.
Geometry.Explode
Separates compound or non-separated elements into their
component parts
Geometry.ImportFromSAT
List of imported geometries
Geometry.Rotate (basePlane)
Rotates an object around the Plane origin and normal by a
specifed degree.
Geometry.Translate
Translates any geometry type by the given distance in the given
direction.
Geometry.Line
CREATE
Line.ByBestFitThroughPoints
Creates a Line best approximating a scatter plot of Points.
Line.ByStartPointDirectionLength
Create a straight Line starting at Point, extending in Vector
direction by specifed length.
Line.ByStartPointEndPoint
Creates a straight Line between two input Points.
Line.ByTangency
Create a Line tangent to the input Curve, positioned at the
parameter Point of the input Curve.
QUERY
Line.Direction
The direction of the Curve.
Geometry.NurbsCurve
Create
NurbsCurve.ByControlPoints
Create a BSplineCurve by using explicit control points.
NurbsCurve.ByPoints
Create a BSplineCurve by interpolating between points
qcomm
Geometry.NurbsSurface
Create
NurbsSurface.ByControlPoints
Create a NurbsSurface by using explicit control Points with
specifed U and V degrees.
NurbsSurface.ByPoints
Creates a NurbsSurface with specifed interpolated points and U
and V degrees. The resultant surface will pass through all of the
points.
Geometry.Plane
CREATE
Plane.ByOriginNormal
Create a Plane centered at root Point, with input normal Vector.
Plane.XY
Creates a plane in the world XY
Geometry.Point
CREATE
Point.ByCartesianCoordinates
Form a Point in th egiven coordinate system with 3 cartesian
coordinates
Point.ByCoordinates (2d)
Form a Point in the XY plane given two 2 Cartesian coordinates.
The Z component is 0.
Point.ByCoordinates (3d)
Form a Point given 3 Cartesian coordinates.
Point.Origin
Get the Origin point (0,0,0)
ACTIONS
Point.Add
Add a vector to a point. The same as Translate (Vector).
QUERY
Point.X
Get the X component of a point
Point.Y
Get the Y component of a point
Point.Z
Get the Z component of a point
Geometry.Polycurve
CREATE
Polycurve.ByPoints
Make PolyCurve from sequence of lines connecting points. For
closed curve last point should be in the same location as the start
point.
Geometry.Rectangle
CREATE
Rectangle.ByWidthLength (Plane)
Create a Rectangle centered at input Plane root, with input width
(Plane X axis length) and (Plane Y axis length).
Geometry.Sphere
CREATE
Sphere.ByCenterPointRadius
Create a Solid Sphere centered at the input Point, with given
radius.
Geometry.Surface
CREATE
Surface.ByLoft
Create a Surface by lofting between input cross section Curves
Surface.ByPatch
Create a Surface by flling in the interior of a closed boundary
defned by input Curves.
ACTIONS
Surface.Offset
Offset Surface in direction of Surface normal by specifed
distance
Surface.PointAtParameter
Return the Point at a specifed U and V parameters.
Surface.Thicken
Thicken Surface into a Solid, extruding in the direction of Surface
normals on both sides of the Surface.
Geometry.UV
CREATE
UV.ByCoordinates
Create a UV from two doubles.
Geometry.Vector
CREATE
Vector.ByCoordinates
Form a Vector by 3 Euclidean coordinates
Vector.XAxis
Gets the canonical X axis Vector (1,0,0)
Vector.YAxis
Gets the canonical Y axis Vector (0,1,0)
Vector.ZAxis
Gets the canonical Z axis Vector (0,0,1)
ACTIONS
Vector.Normalized
Get the normalized version of a vector
Operators
+
Addition
-
Subtraction
*
Multiplication
/
Division
%
Modular Division fnds the remainder of the frst input after
dividing by the second input
<
Less Than
>
Greater Than
==
Equality tests for equality between two values.
Dynamo Packages
Here are a list of some of the more popular packages in the Dynamo community. Developers,
please add to the list! Remember, the Dynamo Primer is open-source!
These example fles accompany the Dynamo Primer, and are organized according to Chapter and
Section.
Introduction
What is Visual
Visual Programming - Circle Through Point.dyn
Programming
Presets Presets.dyn
Surface.sat
List-FilterByBooleanMask.dyn
List-GetItemAtIndex.dyn
List-Operations.dyn
List-Reverse.dyn
List-ShiftIndices.dyn
Combine.dyn
Flatten.dyn
Map.dyn
ReplaceItems.dyn
Top-Down-Hierarchy.dyn
Transpose.dyn
n-Dimensional-Lists.sat
Shorthand Obsolete-Nodes_Sine-Surface.dyn
Functions Functions_SphereByZ.dyn
Dynamo for Revit
Selecting Selecting.dyn
ARCH-Selecing-BaseFile.rvt
Editing Editing.dyn
ARCH-Editing-BaseFile.rvt
Creating Creating.dyn
ARCH-Creating-BaseFile.rvt
Customizing Customizing.dyn
ARCH-Customizing-BaseFile.rvt
Documenting Documenting.dyn
ARCH-Documenting-BaseFile.rvt
Dictionaries in Dynamo
Custom Nodes
Packages