Documente Academic
Documente Profesional
Documente Cultură
Getting Started
Installing Grasshopper
Grasshopper is a graphical algorithm editor tightly integrated with Rhinos 3-D modeling tools and after a few
quick steps you will be able to create your very own parametric designs. To download the plug-in, visit
http://www.grasshopper3d.com and click on the Download link on the upper menu bar.
Note: There are two different plug-in versions available for download. As of this writing, the "Current Build" is
based off of version 0.5.0099 which was released to the public in December 2008. While this build is stable,
it lacks some of the enhanced features and data structure capabilities that the "Work-In-Progress" builds
have incorporated. For this reason, we will be using the most recent WIP build version 0.6.0059 for the
tutorials found in this Primer.
Now, select the Work-In-Progress link from the drop-down menu and you will be redirected to a new page
which has a list of all the new public releases and the upgraded features of each edition. Select the EXE
installer (or ZIP installer if your admin privileges will not allow EXE downloads) and save the file to your hard
drive. The file cannot be loaded over a network connection so the file must be saved locally to your
computers hard drive.
Double-click on the .EXE file that you just downloaded and follow the on screen instructions to install the WIP
version on your computer. That's it. Now we're ready to begin!
The Interface
C. Component Palettes
This area organizes components into categories and sub-categories. Each component belongs to a unique
category and sub-category. Categories are displayed as tabs, and sub-categories are displayed as dropdown panels.
As we just explained, all components belong to a certain category. These categories have been labeled to
help you find the specific component that you are looking for (such as "Params" for all primitive data types or
"Curves" for all curve related tools... so on and so forth).
Since there can be many more components in each sub-category than will fit into the palette, a limited
number of icons are displayed on each panel. The height of the component palette and the width of the
Grasshopper window can be adjusted to display more or fewer components per sub-category.
To see a menu of all of the components in a given sub-category, simply click on the black bar at the bottom
of each panel. This will open the sub-category menu which provides access to all components in that subcategory.
To add a component to the canvas, you can either click on the objects in the drop-down menu or you can
drag the component directly from the menu onto the canvas. Clicking on items in the sub-category panel will
automatically place them on the toolbar for easy future reference.
Fig 2.1.1 Drag + Drop the components from the component palette to add a component onto the canvas.
Although a lot of thought has gone into the placement of each component on the component panel so that it
would be the most intuitive for new users, people sometimes find it difficult to locate a specific component
that might be buried deep inside one of the category panels. Fortunately, you can also find components by
name, by double-clicking anywhere on the canvas. This will invoke a pop-up search box. Simply type in the
name of the component you are looking for and you will see a list of parameters or components that match
your request.
Fig 2.1.2 Double-click anywhere on the canvas to invoke a key word search for a particular component
found in the Component Panels.
A. The Sketch Tool: The sketch tool works similarly to the pencil tool set found in Adobe Photoshop
with a few added features. Default controls of the sketch tools allow changes in line weight, line type,
and color. However, you may notice that it can be quite difficult to draw straight lines or pre-defined
shapes by using the sketch tool alone. By right-clicking on the selected sketch object you can
choose to simplify your line to create a smoother effect. However, if this still isn't enough, you can
bring any 2d shape that you have pre-defined in Rhino. Simply, right-click on your sketch object and
select "Load from Rhino". When prompted, select any pre-defined shape in your Rhino scene (This
can be any 2d shape like a rectangle, circle, star...etc). Once you have selected your referenced
shape, hit Enter, and your previously drawn sketch line will be reconfigured to your Rhino reference
shape.
Note: Your sketch object may have moved from its original location once you have chosen to load a
shape in from Rhino. Not to worry. Grasshopper always re-centers your sketch object back in the
upper left hand corner of your canvas after it has loaded the shape into the canvas. Check this
location first if you've followed all of the previous steps but can't seem to find where your sketch
object has been moved to.
B. Zoom Defaults: As the name suggests, these are default zoom settings that allow you to zoom in or
out of your canvas at pre-defined intervals.
C. Zoom Extents: This tool allows you to zoom to the extents of your definition; or by selecting one of
the sub-menu items you can zoom to a particular region within your definition. There is also a new
'Zoom Selected' button which will automatically zoom to fit any number of selected components
inside the canvas window.
D. The Navigation Map: The Navigation Map pops open a smaller diagrammatic window of the canvas
which allows you to quickly move around the canvas without having to scroll and pan around the
canvas without having to use the click-wheel or middle mouse button. Photoshop users will find this
feature very similar to the Navigator Window.
E. Named Views: This feature exposes a menu allowing you to store or recall any view area in your
definition.
F. Enable Preview for Selection: Perhaps one of the best new features is the Preview Selection On/Off
toggle (Icons E & F). By selecting the man without the blindfold (the one who can see), any currently
selected components will have their previews set to the 'On' or visible state.
G. Disable Preview for Selection: Conversely, by choosing the man with the blindfold (or the one who
cannot see) you can turn multiple component previews off with one click.
H. Enable Selection: The Enable Selection icon provides the user the ability to turn multiple disabled
components on with a single click.
I. Disable Selection: As the name suggests, the Disable Selection icon will disable the solution of any
currently selected components. Any down-stream components from a disable component will not be
processed at the solution is rebuilt.
J. Rebuild Solution: This button forces a complete rebuild of the Grasshopper solution. You can also
hit the hotkey F5 to force invoke this command as well.
K. Enable/Disable Solver Switch: This toggle allows the user to completely switch on or off
Grasshopper updates. This global switch replaces the Rhino events and Grasshopper events toggles,
which were document bound.
L. The Bake Button: This button turns all selected components into actual Rhino objects and places the
new geometry on the current Layer. However, you now have the ability to specify specific attributes
about an object before baking them into your scene.
The Bake Attributes menu can be invoked by right-clicking on each individual component and
selecting the Bake button within its sub-menu. This dialogue box will allow you to control each
object's name, layer, color, decorations (if applicable), display type, mode setting, group settings,
and any user defined attributes.
M. Preview Settings: Grasshopper geometry is previewed by default, meaning its geometry is visible
inside the Rhino viewport. You can disable the preview on a per object basis by right-click each
component and de-selecting the preview feature, but you can also override the preview for all objects
by using the Preview Settings on the canvas tool bar. Switching off the Shaded preview can increase
the speed of some scenes that have many curved or trimmed surfaces.
N. Hide button: This button hides the canvas toolbar. You can always switch it back on through the
View drop-down menu on the Main Menu Bar.
F. The Canvas
This is the actual editor where you define and edit the history network. The Canvas hosts both the objects
that make up the definition and some UI widgets (see section G).
Objects on the canvas are usually color coded to provide feedback about their state:
A. A parameter which contains warnings is displayed as an orange box. Most parameters are orange
when you drop them onto the canvas since the lack of data is considered to be a warning.
B. A parameter which contains neither warnings nor errors is shown in light gray.
C. A component is always a more involved object, since it contains input and output parameters. This
particular component has at least 1 warning associated with it because it is displayed as an orange
box. You can find warning and errors through the context menu of objects or on the Status Bar (see
section H: The Status Bar).
D. A component which contains neither warnings nor errors is also shown in light gray.
E. A component whose preview has been disabled is shown in a slightly darker gray. There are two
ways to disable a components preview. First, simply right-click on the component and toggle the
preview button. To disable the preview for multiple components at the same time, first select the
desired components and then toggle the disable preview icon (blindfolded man) on the Canvas
Toolbar.
F. A component that has been disabled is shown in a dull gray. Disabled components will render all
down-stream components inactive. To disable a component you may right-click on the component
and toggle the disable button, or you may select the disable selection icon on the canvas toolbar
after having selected the desired components.
G. A component which has been selected will be shown in a light green color. If the selected
component has generated some geometry within the Rhino scene, this will also turn green to give
you some visual feedback.
H. A component which contains at least 1 error is displayed in red. The error can come either from the
component itself or from one of its input/output parameters. We will learn more about component
structures in the following chapters.
The Find Feature: In Section C, we discussed how difficult it can become trying to locate one of the
hundreds of components that are available in the Component Panels. The quick solution is to doubleclick anywhere on the canvas to launch a search query for the component you are looking for. However,
what if we need to find a particular component already placed on our canvas? No need to worry. By
right-clicking anywhere on the canvas, you can invoke the new Find feature. Start by typing in the name
of the component that you are looking for. The Find feature employs the use of some very sophisticated
algorithms which search not only for any instances of a components name within a definition (a
components name is the title of the component found under the Component Panel which we as users
cannot change), but also any unique signatures which we may have designated for a particular
component (also known as nicknames). The Find feature can also search for any component type on the
canvas. Once the Find feature has found a match, it will automatically grey out the rest of the definition
and draw a dashed line around the highlighted component. If multiple matches are found, a list of
components matching your search query will be displayed in the Find dialogue box and hovering over a
item in the list will turn that particular component on the canvas green. A small arrow will also be
displayed next to each item in the list which points to its corresponding component on the canvas. Try
moving the Find dialogue box around on the canvas and watch the arrows rotate in to keep track of their
components.
Fig 2.1.3 The Find feature can be quite helpful to locate a particular component on the canvas. Right-click
anywhere on the canvas to launch the Find dialogue box.
Grouping: One of the most useful new additions to the Grasshopper interface has been the ability to
visually link several components together in group. In addition to being an extremely useful tool for
organizing your definitions, this new feature allows you the ability to quickly select and move multiple
components around the canvas. You can create a group by typing Ctrl+G with the desired components
selected. An alternate method can be found by using the Group Selection button under the Edit Menu on
the Main Menu Bar. Custom parameters for group color, transparency, name, and outline type can be
defined by right-clicking on any group object. You can also nest groups inside of other groups, enabling you
to create layers of organizational data in your definitions. The following images show a few different
grouping methods.
Fig 2.1.4 The image above shows a group of components delineated by the Box Outline profile.
Fig 2.1.5 You can also define a group using a meta-ball algorithm by using the Blob Outline profile.
Fig 2.1.5 Two groups are nested inside one another in the image above. The color (light pink) has been
changed on the outer group to help visually identify one group from the other.
10
G. UI Widgets
There are a few UI (User Interface) widgets that are available in Grasshopper. The first is the Compass
which is shown in the bottom right corner of the canvas. The Compass widget provides a graphical
navigation device to show where your current canvas viewport is in relation to the extents of the entire
definition. This UI widget can be enabled or disabled through the View menu on the Main Menu Bar.
Another useful UI widget which can help you keep your canvas clean is the Align Tool. You can access the
Align Tools by selecting multiple components at the same time and clicking on one of the options found in
the dashed outline that surrounds your selected components. You can align {left, vertical center, right} or
{top, horizontal center, bottom} or distribute components equally through this interface. When first starting
out, you may find that these tools sometimes get in the way (I can tell you that I often make the mistake of
collapsing several components on top of each other). While these tools can be very useful, you can disable
this feature (if needed) by deselecting the Align Tools UI widget from the View Menu on the Main Menu Bar.
A new Profiler widget has been added to the list of UI features (off by default). The profiler lists worst-case
runtimes for parameters and components, allowing you to track down bottlenecks in networks and to
compare different components in terms of performance.
The Profiler widget gives you visual feedback as to which components in your definition could be causing
longer computational times. In the example above, we see that the Square Point Grid component takes a
maximum of 178 milliseconds to generate its point grid and takes 80% of the total time needed to solve the
entire definition. The Profiler widget can be used as a means to optimize your definition. Since this example
is fairly simple, there isnt much room for optimization. However, this feedback can be very useful in longer
definitions. As these Profiler labels can take up precious screen real estate, you may decide to turn these
analysis tools on or off as needed. You can enable/disable this widget under the View Menu on the Main
Menu Bar.
I. Markov Widget
This widget uses Markov chains to 'guess' which component you want to use next based on your behavior in
the past. A Markov chain is a process that consists of a finite number of states (or levels) and some known
probabilities. It can take some time for this widget to become accustomed to a particular user, so dont
11
expect miracles right away, but over time you should begin to notice that this widget will begin to suggest
components that you may want to use next.
The Markov Widget can suggest up to three possible components depending on your recent activity. You
can find a description of Markov probabilities by typing in GrasshopperMarkovChainDescription in the Rhino
command prompt.
Fig 2.2.1 The revamped Remote Control Panel offers a minimal interface for controlling your parametric
definitions.
12
A. Blue feedback means you are currently making a selection in the Rhino Viewport.
B. Green geometry in the viewport belongs to a component which is currently selected.
C. Red geometry in the viewport belongs to a component which is currently unselected.
D. Point geometry is drawn as a cross rather than a rectangle to distinguish it from other Rhino point
objects.
13
Grasshopper Objects
Parameters contain data, meaning that they store stuff. Components contain actions, meaning that they do
stuff. The following image shows some of the possible objects you are likely to encounter in a Grasshopper
definition:
A. A parameter which contains data. Since there is no wire coming out the left side of the object, it does not
inherit its data from elsewhere. Parameters which do not contain errors or warnings are thin, black
blocks with horizontal text.
B. A parameter which contains no data. Any object which fails to collect data is considered suspect in a
Grasshopper definition since it appears to be wasting everyone's time and money. Therefore, all
parameters (when freshly added) are orange, to indicate they do not contain any data and have thus no
functional effect on the outcome of the solution. Once a parameter inherits or defines data, it will become
black (see point A above).
an orange sheen to them. Since a component is likely to contain a number of input and output
parameters, it is never clear which particular object generated the warning by just looking at the
component. There may even be multiple sources of warnings. You'll have to use the context menu (see
below) in order to track down the problems.
Note: Warnings do not necessarily have to be fixed. They may be completely legit.
F. A component containing errors is always shown with a red sheen to them. Similar to warnings, it is not
possible to see where the error was generated in a component just by looking at the component. You'll
14
G. A connection. Connections always appear between an output and an input parameter. There is no limit
to how many connections any particular parameter may contain, but it is not allowed to create a setup
with cyclical/recursive connections. Such a recursion is detected and the entire solution is short-circuited
when it occurs, resulting in an error message in the first component or parameter that was detected to
be recursive. For more information on connections, see the chapter about Data Inheritance.
A. The three input parameters of the Division component. By default, parameter names are always
extremely short. You can rename each parameter as you please.
B. The Division component area (usually contains the nickname of the component)
Note: You can choose whether or not you want to show the nickname of the component or whether you
would rather display the component icon. This can be controlled in two different ways. First, you can set the
"Draw Icons" button under the View tab on the Main Menu Bar. This button sets the status globally so that all
icons in your definition will change automatically. You can also control the Nickname or Icon status on each
individual component by right-clicking the Division component area and changing the toggle found next to
the name area (at the top). The component below shows the difference between the two naming
conventions.
15
Here you see the main component menu, with the cascading menu for the "R" input parameter. The menu
usually starts with an editable text field that lists the name of the object in question. You can change the
16
name to something more descriptive, but by default all names are extremely short to minimize screen-realestate usage. The second item in the menu (Preview flag) indicates whether or not the geometry
produced/defined by this object will be visible in the Rhino viewports. Switching off preview for components
that do not contain vital information will speed up both the Rhino viewport frame-rate and the time taken for a
solution (in case meshing is involved). If the preview for a parameter or a component is disabled, it will be
drawn with a faint white hatch. Not all parameters/components can be drawn in viewports (numbers for
example) and in these cases the Preview item is usually missing.
The context menu for the "R" input parameter contains the orange warning icon, which in turn contains a list
(just 1 warning in this case) of all the warnings that were generated by this parameter.
17
The parameter is orange, indicating it generated a warning. It's nothing serious, the warning is simply there
to inform you that the parameter is empty (it contains no persistent records and it failed to collect volatile
data) and thus has no effect on the outcome of the solution. The context menu of the Parameter offers 2
ways of setting persistent data: single and multiple:
Once you click on either of these menu items, the Grasshopper window will disappear and you will be asked
to pick a vector in one of the Rhino viewports:
18
Once you have defined all the vectors you want, you can press Enter and they will become part of the
Parameters Persistent Data Record. This means the Parameter is now no longer empty and it turns from
orange to black:
At this point you can use this parameter to 'seed' as many objects as you like with identical vectors.
19
At this stage, all the objects are unconnected and we need to start hooking them up. It doesn't matter in what
order we do this, but lets go from left to right. If you start dragging near the little circle of a parameter (what
us hip people call a "grip") a connecting wire will be attached to the mouse:
Once the mouse (with the Left Button still firmly pressed) hovers over a potential target Parameter, the wire
will attach and become solid. This is not a permanent connection until you release the mouse button:
20
We can do the same for the "Y" parameter of the PtGrid component and the "A" and "B" parameters of the
Line component: Click+Drag+Release...
21
Note that we can make connections both ways. But be careful, by default a new connection will erase
existing connections. Since we assumed that you will most often only use single connections, you have to
do something special in order to define multiple sources. If you hold Shift while dragging connection wires,
the mouse pointer will change to indicate addition behavior:
If the "ADD" cursor is active when you release the mouse button over a source parameter, that parameter will
be added to the source list. If you specify a source parameter which is already defined as a source, nothing
will happen. You cannot inherit from the same source more than once.
By the same token, if you hold down Control, the "REM" cursor will become visible, and the targeted source
will be removed from the source list. If the target isn't referenced, nothing will happen.
22
You can also disconnect (but not connect) sources through the parameter menu:
Here, a dashed connection wire is shown between the source component and the receiver because the
wireless component is currently selected.
23
The number 1 before the input of the receiver component indicates that there is one connection being fed
into its input. However, since the receiver component is not selected, the connection wire no longer appears
(but the information is still transferred).
A. List If the information flowing out of a component contains a list of information, the wire type will be
shown as a grey double line. In this example, the line parameter contains two lines which are being
fed into the Divide Curve component.
Note: Any parameter that contains more than one item is considered a list, which should make
intuitive sense.
B. Single Item The data flowing out of any parameter that contains a single item (including sliders)
will be shown with a solid grey line.
C. Tree Information transferred between components which contain a data structure will be shown in
a grey double-line-dash wire type. In this example, we have two paths, each with 6 items on each
path. See Chapter 8 for more information on Data Structures.
D. Empty Item An orange wire type indicates that no information has been transferred. Since our
parameter component is orange as well, we know that this component has generated some warning
message. In this case, it simply means that the parameter contains no data, and thus no information
is being sent across the wire.
You can also Extract Parameters from any input node of a component. Simply, right-click on any input
parameter of a component and select Extract Parameter to pull out a new component with that particular
input.
24
As you can see there are different ways in which we can draw lines between these sets of points. The
Grasshopper plug-in currently supports three matching algorithms, but many more are possible. 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:
The "Longest List" algorithm keeps connecting inputs until all streams run dry. This is the default behavior
for components:
This is potentially dangerous since the amount of output can be humongous. The problem becomes more
intricate as more input parameters are involved and when the volatile data inheritance starts to multiply data,
but the logic remains the same.
25
Lets take a look at a simple example. Imagine we have a point component which inherits its x, y and z
values from remote parameters which contain the following data:
X coordinate: {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, and 9.0} (list of 10 integers)
Y coordinate: {0.0, 1.0, 2.0, 3.0, and 4.0} (list of 5 integers)
Z coordinate: {0.0, and 1.0} (list of 2 integers)
If we combine this data in the "Shortest List" fashion, we get only two points since the "Z coordinate"
contains only two values. Since this is the shortest list it defines the extent of the solution:
Fig. 6.1.1 The shortest list algorithm creates only two points in this example.
26
However, if we choose to use the "Longest List" algorithm, we will create ten points, recycling the highest
possible values of the Y and Z streams:
Fig. 6.1.3 The cross reference algorithm creates a three dimensional grid of 100 points (10 points in the Xaxis, 5 points in the Y-axis, and 2 points in the Z-axis).
27
Note: Every component can be set to obey one of these rules. The data matching algorithm setting is
available in the menu by right clicking on the component icon.
28
Now that we know a little bit about how the Grasshopper interface works, lets take a look at some of the
different component categories, starting with the Scalar tab at the top of the Component Panel. Scalar
Component types are what you would typically use for various mathematical operations and consist of the
following sub-categories:
A. Constants - These return a constant value such as Pi, Golden Ratio, etc...
B. Domain - Domains are used to define a range of values (formerly known as intervals) between a set of
C.
D.
E.
F.
numbers (typically between a lower limit {A} and an upper limit {B}). There are many components
under the Domain tab that allow you to create or decompose different domain types which we will cover
in more detail later in this chapter.
Operators - Operators are used in mathematical operations such as Adding, Subtracting, Multiplication,
etc There are also a handful of conditional operators found in this sub-category which allow you to
determine whether a set of numbers are larger than, less than, or similar to another set of number.
Polynomials - Polynomials are one of the most important concepts in algebra and throughout
mathematics and science. They are used to form polynomial equations, which encode a wide range of
problems, from elementary word problems to complicated problems in the sciences. You can use the
handful of polynomial components found in this subcategory to compute factorials, logarithms, or to
raise a number to the nth power.
Trigonometry As the name implies, these components allow you to solve trigonometric functions such
as Sine, Cosine, and Tangent, etc.
Utility The utility subcategory is a grab bag of useful components that can be used in various
mathematical equations. Check here if youre trying find the maximum or minimum values between two
lists of numbers; or if youd rather compute the statistical mean of a set of numbers or solve a mass
addition function.
7.1 Operators
As we previously discussed, Operators are a set of components that use algebraic functions with two
numeric input values, which result in one output value. To further understand Operators, we will create a
simple mathematical definition to explore the different Operator component types.
Fig 7.1.1 The example shows how we can easily convert a decimal value to its nearest integer and then
perform various scalar operations on those values.
29
Useful Tip: Before we begin, I should explain how this manual has been set up to help you find the
components in each tutorial. In the tutorial below, youll see a list of instructions which will walk you through
each example. After each step number, you may see a list of words followed by forward slashes: eg.
Params/Special/Number Slider. This is the addresses to the component that you are looking for. So if you
were looking to add a numeric slider to the canvas; you will find that component under the Params Tab. You
would then you click on the black bar found at the bottom of the subcategory labeled Special. That should
bring up a drop down list of every component within that subcategory which is where you will find the
numeric slider. Drag+drop the numeric slider on to the canvas and then proceed to the next step.
Params/Special/Number Slider Drag and drop a numeric slider component to the canvas
Double click the slider to set:
Value: 50.0
Note: the Value parameter is arbitrary and can be modified to any value within the upper and lower
limits.
3.
4.
5.
6.
7.
8.
30
probably noticed that we could have simplified this step by just setting the slider type to integers at
the beginning. But, youll find that there are always several ways to skin a cat in Grasshopper (for
lack of a better term). From now on, we will simply set our slider type to integers (if we need whole
numbers) to save on screen real estate, but there may be specific times where we will feed some
numeric data into a primitive parameter like this. Now, when we connect a Post-It panel
(Params/Special/Panel) to the output value of each Integer component, we can see the conversion
happening in real-time. Move the slider to the left and right and note that the floating point values
are being converted to whole numbers on the fly.
9.
10.
11.
12.
13.
14.
15.
16.
17.
Subtraction
Multiplication
Division
Modulus
Power
Connect the first Integer component to each of the Operators-A input value
Connect the second Integer component to each of the Operators-B input value
Drag and drop a five more Post-it panels onto the canvas and connect one panel to each Operators
output value
Congratulations! Youve just made your first calculator via Grasshopper. You should now see the result of
each Operators action in the Post-it panel area as you change each of the numeric sliders.
You probably noticed that there were a few other components under the Operators subcategory that we
didn't cover. There are 4 conditional operator components that act somewhat differently than the
mathematical operators, in that they compare two lists of data and return a boolean value (True or False)
instead of performing a algebraic expression. Lets take a look at the Equality, Similarity, Larger Than, and
Smaller Than components. See example definition on facing page for reference numbers.
A. The Equality component takes two lists and compares the first item of List A to the first item of List B. If
the two values are the same, then a True boolean value will be returned. Conversely if the two values are
not equal, then a False boolean value will be returned. The component cycles through the lists
according to the data matching algorithm (see Chapter 6 for more information on data matching). There
are two outputs for this component. The first returns a list of boolean values that are equal to one
another. The second output returns a list that is not equal to one another or to put it another way; the
second output returns a list that is inverted from the first output.
B. The Similarity component evaluates two lists of data and tests for the similarity between two numbers. It
is almost identical to the way in which the Equality component compares the two lists, with one
exception. The Similarity component has a percentage input that defines the ratio of list A that list B is
allowed to deviate before inequality is assumed. The Similarity component also has an output that
determines the absolute value distance between the two input lists.
C. The Larger Than component determines whether the first item of List A is greater than the first item of
List B. Depending on your application, you may decide to use one of the two outputs. The first will
evaluate whether List A is greater than (>) List B, while the second will allow you to evaluate a greater
than or equal to (>=) condition.
31
D. The Smaller Than component performs the inverse operation to the Larger Than component. The
Smaller Than component determines whether list A is less than list B and will returns a list of boolean
values. Similarly, the two outputs let you determine whether or not you would like to evaluate each list
according to a less than (<) or less than and equal to (<=) condition.
Fig 7.1.2 The example definition above takes a look at various conditional operations between two lists.
32
The Range component, found under Logic/Sets/Range, creates a list of evenly spaced numbers between a
low and a high value called the domain of the numeric range. In the example above, two numeric sliders are
connected to the input values of the Range component. The first slider (called Domain) is connected to the
D-input which defines the numeric domain for the Range component. If a single value is connected to the Dinput of the Range component then the domain will always range from 0 to whatever number has just been
connected to the input node. In the case above, the domain has been defined from zero to one, since the
slider is set to 1. The second slider (called Steps) defines the number of divisions between the domain. This
may seem a little counter-intuitive because even though we have input the number 10; our resultant list will
contain 11 numbers. This is because we have defined the number of divisions and not the number points.
The image below graphically shows why this is the case.
So, what could we do if we wanted to create a range between two numbers that didn't start at zero?
Fortunately, there is a simple way to create a numeric domain between two different numbers. We can use a
Domain Component which can be found under Scalar/Domain/Domain.
Note: There are many different domain components so make sure to use the component that creates a
numeric interval between two numeric extremes. We will cover some of the other domain components in
upcoming chapters.
The Domain component simply creates a interval between two numbers. In the case below, we have
connected two sliders to both the A and B inputs of the Domain component so that we can create a new
domain between 10.0 and 20.0. We can then connect the output of the Domain component into the D-input
of the Range component to redefine the numeric extremes of our list of numbers.
The Series component is similar to the Range component, in that, it also creates a list of numbers. However
a Series component is different because it creates a set of discreet numbers based on a start value, step
size, and the number of values in the Series. The example on the facing page shows three numeric sliders
connected to the Series component. The first slider, when connected to the S-input, defines the starting
33
point for the series of numbers. The second slider, set to 10, defines the step value for the series. Since, the
start value has been set to 1 and the step size has been set to 10, the next value in the series will be 11.
Finally, the third slider defines the number of values in the series. Since this value has also been set to 10,
the final output values defined in the series shows 10 numbers that start at 1 and increase by 10 at each
step.
The Duplicate Data (Logic/Sets/Duplicate) component (as the name suggests) creates duplicates of a given
list of data. Data can be duplicated in one of two ways, either copies of the original list are appended to the
end of the list until the predefined number of duplicates has been reached, or each data item is duplicated a
number of times before moving onto the next item. An example of the Duplicate operation can be seen
above where the original list order is retained. In this example, we have used the Series component to
create a list from 1 to 10. This will be the list of items that we will duplicate. By specifying a True boolean
value for the O-input (retain list order) of the duplicate data component, the original list will be kept intact.
Thus, the duplicated list has 20 values in the list; where the first ten values are composed of the original list,
and the second ten values are a duplicate of that list.
34
If, however, we choose not to retain the original list order by specifying a False boolean value for the O-input,
then we will get a completely different duplicated list. This time, it duplicates each index item twice (the
number of duplicates specified in the N-input) before moving onto the next item.
The Repeat Data component (Logic/Sets/Repeat Data) behaves very similarly to the Duplicate Data
component we just covered. The main difference is that the list order is always retrained (see Duplicate Data
with True boolean value) and you have to specify the length of desired output list. Thus, in the example
above, we have specified a repeated list length of 15 (L-input) so the D-output results in exactly 15 values.
The list repeats until it reaches the list length.
35
The Random Component (Logic/Sets/Random) can be used to generate a list of pseudo random
numbers. They are referred to as pseudo random because the number sequence is unique but stable for
each seed value. Thus, you can generate an entirely new set of random numbers by changing the seed
value (S-input). The domain, as in the previous example, is a defined interval between two numeric
extremes. Since we have connected a single value (in this case 10.0) to the R-input, the domain will be
created from 0.0 to 10.0. Additionally, since the number of values slider has also be set to 10, the Random
component will create ten random values somewhere between 0 and 10. We can change the seed value to
generate a completely new set of numbers. The I-input (Integers Only Boolean) specifies whether or not the
Random component should output floating point values (decimal numbers) or integers.
The Jitter Component (Logic/Sets/Jitter) randomly shuffles a list of values. The input list is reordered
based on random noise. Jittering is a good way to get a random set with a good distribution. The jitter
strength (J-input) sets radius of the random noise. Thus, if the jitter strength equals 0.5, then each item is
allowed to reposition itself randomly to within half the span of the entire set. If that parameter is set to 1.0,
then each value can relocate to any new position within the list. In the example below, the random number
sequence created in the Random example above is completely reshuffled by using the Jitter component. No
new values have been created. Instead, the existing values are just moved around.
Youre probably now asking yourself how these components to generate something other than just a list of
numbers. In this next tutorial, well walk through how we can use both the Random and Jitter components to
create a randomly spaced three dimensional matrix of colored spheres.
36
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
Note: Because we have set the Jitter Strength slider to 1.0 (max jitter falloff) we will completely shuffle all
200 values that were generated by the Random component.
21. Now, select the Jitter component and type Ctrl+C (Copy) and Ctrl+V (Paste) to create another
component
22. Right-click on the S-input of the second Jitter component and Set the Integer to 2.0
23. Vector/Point/Point XYZ Drag and drop a Point XYZ component
24. Connect the R-output of the Random component to the X-input of Point XYZ component
25. Connect the R-output of the first Jitter component to the Y-input of the Point XYZ component
26. Connect the R-output of the second Jitter component to the Z-input of the Point XYZ component
Note: You should now see a randomly spaced three dimensional matrix of points. This point grid fills a
maximum volume of 10x10x10 because we have specified our domain to range from 0.0 to 10.0.
37
Fig. 7.3.1 In the first part of the definition, we have created three random sets of values (one random
component and two shuffled lists) which have defined the X, Y, and Z coordinates of 200 points.
27.
28.
29.
30.
31.
32.
Note: You should now see a series of spheres that are centered on each of the points in the random
point matrix. Youll notice that the spheres grow in size the farther away they are from the Y-axis. Try
changing the connection feeding the A-input of the Division component. Try replacing this connection
with the R-output of the first Jitter component. You should notice the spheres are now scaling along the
X-axis. Again, try replacing this connection with the R-output from the other Jitter component. Were
using the Division component to reduce the radius of the spheres. Lets take this definition a little bit
further by adding a little bit of color to our definition.
Fig 7.3.2 The definition above will create 200 randomly spaced and scaled spheres.
33.
34.
35.
36.
37.
38.
38
Note: The Gradient Component has three inputs. The L0 is the lower limit of the gradient range while the
L1 is the upper limit of this range. The t-value is some value that falls somewhere between these limits.
The default value for L0 is 0.0 and is 1.0 for L1. Because weve divided our random values by the
domain maximum, our output values from the Division component will always fall somewhere between 0
and 1. This Gradient is then being used to define the shader values (S-input) of a Custom Preview
component.
Fig 7.3.3 Right-click on the Gradient Component to change the color presets.
39
Fig 7.4.1 - Since our slider has been set to some value greater than
the number 5; our resultant Boolean value will be True.
40
Once we have determined the boolean value of the function, we can feed the True/False pattern information
into a Dispatch component (Logic/List/Dispatch) to perform a certain action. The Dispatch component
works by taking a list of information and filters the information based on the boolean pattern that was
generated from the single variable function. If the pattern shows a True value, the list information will be
passed to the Dispatch-A output. If the pattern is False, it passes the list information to the Dispatch-B
output.
For this example, we have decided to create a circle ONLY if the slider value is greater than 5. We have
connected a Circle component (Curve/Primitive/Circle) to the Dispatch-A output, so that a circle with a
radius specified by the numeric slider will be created only if the boolean value passed into the Dispatch
component is True. Since no component has been connected to the Dispatch-B output; if the boolean value
is False, then nothing happens and a circle will not be created.
We can take this definition a little further by connecting an N-sided Polygon (Curve/Primitive/Polygon) to
the Dispatch-B output. Make sure to connect the Dispatch-B output wire to the Polygon R-input to define the
polygons radius. Now, if the numeric slider falls below 5, then a five sided polygon with a radius defined by
the number slider will be created at the origin point. If we take the slider value above 5, then a circle will be
created. By this method, we can begin to create as many If/Else statements as needed to feed information
throughout our definition.
Fig 7.4.3 - This image shows the final definition for the If/Else test. Try changing the curve types that are
connected to A & B Dispatch output nodes to get different results based on the conditional statement.
41
Fig 7.5.2 The image above shows the finished definition for the Vornoi Spiral tutorial.
Lets start this definition from scratch:
1.
2.
3.
4.
5.
42
Note: We have set this slider type to integers because it will be driving the number of points on our
spiral. Logic tells us that we cant create half of a point, so we know we will want to set the rounding
type integers to ensure that we wont get any errors when we create our spiral.
6.
7.
8.
9.
10.
Logic/Script/F1 - Drag and drop a single variable Function component onto the canvas
Right-click the F-input of the Function component and open the Expression Editor
In the Expression Editor dialogue box, type the following equation: x*sin(5*x)
Note: If you have entered the algorithm into the editor correctly, you should see a statement that
says, "No syntax errors detected in expression" under the errors rollout. Click OK to accept the
algorithm.
Fig 7.5.3 - You can type an algorithm into the Expression Editor to solve mathematically complex
solutions. You can also click the button that says Display Function List to see an entire menu of
commands that can be evaluated in the Function component.
11.
12.
13.
Now, select the Function component and hit Ctrl+C (copy) and Ctrl+V (paste) to create a duplicate
Function
Right-click the F-input of the duplicated Function component and open the Expression Editor again
In the Expression Editor dialogue box, type the following equation: x*cos(5*x)
Note: The only difference in this equation is that we have replaced the sine function with a cosine
function. Click OK to accept this algorithm.
14.
15.
16.
17.
43
Note: You should now see a set of points that radiates out from the origin point forming a parametric
spiral. Since we have only connected the list of values coming out of the two Function components
to the X & Y nodes of the Point XYZ component, our spiral will simply be a 2-dimensional pattern.
You can create a 3-dimensional spiral (or helix) by simply connecting the Range-R output to the Zinput of the Point XYZ component.
18.
19.
20.
Fig 7.5.3 - This definition can create an amazing array of patterns by simply changing the values on a
few of the sliders. What patterns can you create?
44
4.
5.
6.
7.
Params/Special/Slider - Drag and drop three numeric sliders onto the canvas
Right-click on the first slider and set the name to Num Pts on Crv
Double-click the Num Pts on Crv slider and set the following parameters:
Rounding: Integers
Lower Limit: 1
Upper Limit: 50
Value: 40
Right-click on the second slider and set the name to Curve Width
Now, double-click the Curve Width slider and set the following parameters:
Lower Limit: 0
Upper Limit: 30
Value: 10
Right-click on the third slider and set the name to Frequency
Double-click on the Frequency slider and set the following parameters:
Rounding: Even
Lower Limit: 0
Upper Limit: 10
Value: 4
45
8.
9.
10.
11.
12.
13.
Logic/Sets/Range - Drag and drop two Range components onto the canvas
Connect the Curve Width slider to the D-input of the first Range component
Scalar/Constants/Pi Drag and drop a Pi component onto the canvas
Connect the Frequency slider to the input of the Pi component
Connect the output of the Pi component to the D-input of the second Range component
Connect the Num Pts on Curve slider to both Range-N inputs
Note: You may be wondering why we connected the Frequency slider to the Pi component. This
method ensures that our trigonometric curve will always complete a complete cycle (essentially
some multiple of Pi). This is a critical step, because we will need the start point of our sinusoidal
curve to coincide with the end point so that when we will have a seamless match when we shift the
curve to the right or to the left (phase shift).
Fig 7.5.1 - Your definition should look like the image above. We have now created two lists of data; the
first is a range of evenly divided numbers from 0 to 10, and the second is a list of evenly divided
numbers ranging from 0 to 4*Pi.
14.
15.
16.
17.
18.
19.
20.
21.
Lower Limit: 0
Upper Limit: 4
Value: 1.5
Scalar/Operators/Multiply Drag and drop a Multiply component onto the canvas
Connect the y-output of the Sine component to the A-input of the Multiply component
Connect the Amplitude slider to the B-input of the Multiply component
Note: Now, if you connect the output of the Multiply component to a Post-it Panel
(Params/Special/Panel) then well notice a very important fact the first and last data items in the list
are exactly the same. This should make sense. That is exactly why we multiplied the Frequency
slider by Pi. However, if we actually shift this list (which is how well accomplish the phase shift) then
well get a duplicate number in our list causing a small hitch in our curve. In order to remedy this
problem, well need to cull (remove) either the first or last item in our list.
46
22.
23.
24.
25.
26.
27.
28.
29.
30.
Logic/Sets/Cull Index Drag and drop a Cull Index component onto the canvas
Connect the R-output of the Multiply component to the L-input of the Cull Index component
Right-click on the I-input of the Cull Index component and Set Integer to 0.0 (the first index item in
the list)
Logic/Sets/Cull Index Drag and drop another Cull Index component onto the canvas
Connect the R-output of the first Range component (the one connected to the Curve Width slider) to
the L-input of this new Cull Index component
Right-click on the I-input of the Cull Index component and Set Integer to 0.0
Vector/Point/Point XYZ - Drag and drop a Point XYZ component onto the canvas
Connect the output of the second Cull Index component to the X-input of the Point XYZ component
Connect the output of the first Cull Index component (the one that is connected to the Multiply
component) to the Z-input of the Point XYZ component
Note: You should see a series of points in the shape of a sine wave in the Rhino viewport. The Xcoordinate of our sine wave is evenly spaced. The Z-component, however, is defined by a list of
values that have been multiplied by Sine, so the y-values undulate and ultimately form a wave
pattern. You can now change any of the numeric sliders to change the shape of the wave pattern.
You can also replace the Sine component with the other Trigonometry component found under the
Scalar Tab (ie. Cosine and Tangent).
Fig 7.5.2 - At this point, your definition should look like the screen shot above. Try replacing the sine
component with one of the other trigonometric functions available like cosine, or tangent. How does
this affect the wave form? Lets take this definition a little further.
15.
16.
17.
19.
20.
21.
22.
23.
24.
25.
Params/Special/Slider - Drag and drop another number slider onto the canvas
Right-click on this slider and set the name to Phase Shift
Double-click on Phase Shift slider and set the following:
Rounding: Integer
Upper Limit: 20
Value: 0
Logic/List/Shift List Drag and drop a Shift List component onto the canvas
Connect the L-output from the first Cull Index component (again, the one connected to the Multiply
component) to the L-input of the Shift List component
Connect the Phase Shift slider to the S-input of the Shift List component
Params/Special/Boolean Toggle Drag and drop a Boolean Toggle onto the canvas
Double-click on the Boolean Toggle to set it to True
Connect the Boolean Toggle to the W-input of the Shift List component
Connect the L-output of the Shift List component to the Z-input of the Point XYZ component
47
Note: This last step should replace your existing connection to the Z-input of the Point XYZ
component. The Shift List component is moving the Z-values up or down the list depending on the
Phase Shift value. A negative Phase Shift value moves the data items in the list downward. A
positive value moves the data items upward. Because we have specified a True wrap value (boolean
toggle) the list length will always remain the same. Essentially, the values that get moved out of the
list get re-appended to the end of the list, creating a continuous loop. Because we Culled the first
number in our original list (see step 23), our Z-values will be seamless regardless of our Phase Shift
value.
26.
27.
28.
29.
30.
31.
32.
Vector/Point/Point XYZ - Drag and drop another Point XYZ component onto the canvas
Connect the output of the second Cull Index component (the one downstream from the Curve Width
slider) to the X-input of the new Point XYZ component
Curve/Primitive/Line - Drag and drop a Line component onto the canvas
Connect the Pt-output from the Point XYZ that is defining our sinusoidal wave from to the B-input of
the Line component
Connect the output of the second Point XYZ component (the points that fall along the X-axis) to the
A-input of the Line component
Curve/Spline/Interpolate Drag and drop an Interpolated Curve component onto the canvas
Connect the Pt-output of the Point XYZ component (again, these are the points defining our wave
form) to the V-input of the Interpolated Curve component
Note: In the last part of the definition, we have created a second set of evenly spaced points along
the X-axis which correspond to the same X-coordinates of the Sine curve. The Line component
creates a line segment between the first list of points - the ones that create the sine curve - and the
second list of points which define the X-axis. The new lines give you a visual reference of the vertical
displacement in the wave form pattern. The Interpolated Curve component passes through each of
the
Fig 7.5.3 Hopefully, if all has gone well your definition will look like the image above.
48
Fig 8.1.1 The above example shows how we (as humans) would count the number of fingers on one hand;
in comparison to the zero-based counting system which Grasshopper uses which always starts a list at index
number zero.
For example, if we were to count the number of fingers we have on our right hand, chance are that you
would have counted from 1 to 5 (unless you have had the unfortunate experience of losing one or more of
your fingers in which case this is a very poor example). However, if this list had been stored in an array,
then our list would have counted from 0 to 4. Note, that we still have 5 items in the list; its just that the array
is using a zero-based counting system. Dont feel bad if this seems confusing. Zero-based counting
systems routinely confuse even the most experienced computer programmers.
Often times the easiest way to take a look at the type of data stored in a list is to connect a Post-it Panel
(Params/Special/Panel) to the output of a particular component. By default, the Post-it Panel automatically
shows all index numbers to the left side of the panel (see Fig.8.1.1) and displays the data items on the right
side of the panel. The index numbers will become a crucial element when we begin to manipulate our lists;
however, we can turn them on and off by right-clicking on the Post-it Panel and clicking on the Entry
Numbers item in the sub-menu. For now, lets leave the entry numbers turned on.
49
50
Well use the example on the previous page to explore various methods for controlling a list of numeric data
using some of the components found under the Logics Tab.
To start, we have used a Series component (Logic/Sets/Series) with a starting value of 0.0, a step value of
1.0, and a count of 10. Thus, the Post-it panel connected to the Series-S output shows the following list of
numbers: 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, and 9.0. Since the start value of our Series component is
zero, our data items will also match our index numbers.
A. Our List (from the Series component) is fed into a List Item component (Logic/List/List Item) in order to
retrieve a specific data item from within a data set. When accessing individual items in a list, we have to
specify the i-input; which corresponds to the index number we would like to retrieve. We can feed a
single integer or a list of integers into the i-input depending on how many items we would like to retrieve.
The L-input defines the base list which we will be analyzing. If the Wrap value (W-input) equals true, then
the index is always remapped (tiled) to be within the valid range of indices. In this example, we have set
the i-input to 5.0 so the List Item component returns the data item associated with the 5th entry number
in our list (which also happens to be 5.0).
B. The List Length component (Logic/List/List Length) essentially measures the length of the List.
Because our lists always start at zero, the highest possible index in a list equals the length of the list
minus one. In this example, we have connected our base List (from the Series component) to the List
Length-L input, showing that there are 10 values in the list.
C. We can invert the order of our list by using a Reverse List component (Logic/List/Reverse List). If we
input an ascending list of numbers from 0.0 to 9.0 into the Reverse List component; the output returns a
descending list from 9.0 to 0.0.
D. The Shift component (Logic/List/Shift List) will either move the list up or down a number of increments
depending on the value of the shift offset. We have connected the Series-S output into the Shift-L input,
while also connecting a numeric slider to the Shift-S input. Lets set the numeric slider type to integers
(by double-clicking on the slider and setting the appropriate rounding type) so that the shift offset will
occur in whole numbers. If we set the slider to -1, all values of the list will move down by one entry
number. Likewise, if we change the slider value to +1, all values of the list will move up by one entry
number. If Wrap equals True, then items that fall off the ends are re-appended. In this example, we have
a shift offset value set to +1, so that our list moves up by one entry number. Now, we have a decision to
make on how we would like to treat the first value. If we set the Wrap value to False, the first entry will be
shifted up and out of the list, essentially removing this value from the data set. However, if we set the
wrap value to True, the first entry will be moved to the bottom of the list.
E. The Cull Nth component (Logic/Sets/Cull Nth) removes every N data entry from the list, where N is
defined as the culling frequency. In this example, we have connected a numeric slider to the N-input.
We have set our slider to 2.0, such that the component removes every other entry from the list. The Cull
Nth-L output reveals a new culled list where every odd entry has been removed from the list resulting in
the following: 0.0, 2.0, 4.0, 6.0, and 8.0. If we change the numeric slider to 3.0, the Cull Nth component
will remove every third number from the list so that the output would be: 0.0, 1.0, 3.0, 4.0, 6.0, 7.0, and
9.0.
F. The Cull Pattern component (Logic/Sets/Cull Pattern) is similar to the Cull Nth component, in that it
removes items from a list based on a defined value. However, in this case, it uses a set of boolean
values that form a pattern, instead of numeric values. If the boolean value is set to True, the data entry
will remain in the list; whereas a false value will remove the data entry from the set. In this example, we
have set the boolean pattern to: True, True, False, False. Since there are only 4 boolean values and our
list has 10 entries, the pattern will be repeated until it reaches the end of the list. With this pattern, the
output list will look like: 0.0, 1.0, 4.0, 5.0, 8.0, and 9.0. The Cull Pattern component kept the first two
entries (0.0 and 1.0) and then removed the next two values (2.0 and 3.0). It continues this pattern until it
51
G. The Cull Index component (Logic/Sets/Cull Index) will remove specified index numbers from a List.
We can feed a single integer or a list of integers into the I-input depending on which data items we would
like to remove from the list. In this example, we have specified index numbers (1.0, 4.0, 5.0, and 8.0) to
be removed from the list; so our resultant list reads 0.0, 2.0, 3.0, 6.0, 7.0, and 9.0.
H. The Sub-List component (Logic/List/Sub List) extracts a subset of list. The subset allows you to copy
a continuous range of elements as a new list. In order to extract a sub-list, we must first create an
interval domain to define the lower limit and upper limit of our subset. To do this, add an Interval
component (Scalar/Interval/Interval) onto the canvas. In this example, we have defined the Subset
start value as 3.0 and the Subset end value as 6.0 so that our resultant Sub-List reads: 3.0, 4.0, 5.0, and
6.0.
I. The Split List component (Logic/List/Split List) does just what you think it might do... it splits a list into
two smaller lists. The splitting index number is the integer where the list will be split into two sub-lists.
The splitting index number indicates the first item in the second list. In this case, we have defined the
splitting index as 5.0; thus our output reads: List A: 0.0, 1.0, 2.0, 3.0, 4.0 and List B: 5.0, 6.0, 7.0, 8.0, and
9.0.
J. The Weave component (Logic/List/Weave) merges two or more lists together based on a specified
weave pattern (P-input). When the pattern and the streams do not match perfectly, this component can
either insert nulls into the output streams or it can ignore streams which have already been depleted. In
this example, we have fed the A-output from the Split component above to the 0-input of the Weave
component. Similarly, we have connected the B-output from the same Split component to the 1-input of
the Weave component. Thus, our output list reads: 0.0, 5.0, 1.0, 6.0, 2.0, 7.0, 3.0, 8.0, 4.0, and 9.0.
Fig 8.2.1 The image above shows the parameters (height, length, and the number of nodes) which we will
use to create the final truss.
52
3.
Vector/Point/Point XYZ Drag and drop a Point XYZ component onto the canvas
Connect the Point XYZ output to the S-input of the Line SDL component
4.
Note: The Point XYZ component already has default values set up (0,0,0) so that our truss will have a
base point at the origin. However, feel free to connect sliders or other number parameters to the X,
Y, and Z input if you would rather locate your truss in a different Cartesian location.
5.
6.
7.
8.
9.
10.
Params/Special/Number Slider Drag and drop a numeric slider onto the canvas
Right-click on this slider and set the name to Truss Length
Now, double-click on the Truss Length slider and set the following:
Rounding Type: Floating Point
Lower Limit: 0.0
Upper Limit: 10.0
Current Value: 10.0
Connect the Truss Length slider to the L-input of the Line SDL component
Note: Were now going to move a copy of the lower chord line to create the upper chord line.
11.
12.
13.
14.
15.
16.
17.
18.
53
Fig 8.2.2 Weve now defined the upper and lower chords of the truss by controlling the Truss Length and
Truss Height sliders.
19.
20.
21.
22.
23.
24.
Curve/Division/Divide Curve Drag and drop two Divide Curve components onto the canvas
Connect the L-output of the Line SDL component to the C-input of the first Divide Curve component
Connect the G-output of the Move component to the C-input of the second Divide curve component
Params/Special/Number Slider Drag and drop a numeric slider onto the canvas
Right-click on this slider and set the name of this slider to Truss Nodes
Double-click on the Truss Nodes slider and set the following:
Rounding Type: Even Numbers
Lower Limit: 0.0
Upper Limit: 20.0
Current Value: 20.0
Note: It is important that we make sure to set the rounding type of this slider to even numbers to
ensure the proper number of division points on our truss.
25.
26.
27.
28.
Connect the Truss Nodes slider to the N-input of both Divide Curve components
Logic/Sets/Cull Pattern Drag and drop two Cull Pattern components onto the canvas
Connect the P-output of the first Divide Curve component (the points associated with the lower chord
line) with the L-input of the first Cull Pattern component
Now, right-click on the P-input of this Cull Pattern component and select Manage Boolean
Collection
Note: Once the Boolean collection manager pops up, youll see a default cull pattern already set up
(notice the False, False, True, True pattern on the upper left side of the manager). Select all of these
values and hit Delete as we will be defining a different pattern.
54
29.
Set the new cull pattern in the boolean collection manager as True, False
Note: Remember that a True boolean value in a Cull Pattern component will keep the corresponding
index item in the input list in tact; while a False boolean value will remove that index item from the
list. With a True, False pattern, we have told the Cull Pattern component to keep the first point in the
list, but then to remove the second point and so on and so forth until it reaches the end of the list.
30.
31.
32.
33.
Fig 8.2.3 At this point, your definition would look like the image above
Note: Now, theres another way for us to define the boolean pattern were using for the Cull Pattern
components. Instead of using the Boolean Collection Manager (as we did in step 28), we can also
use a Post-it Panel with the Multiline Data checkbox unchecked.
Fig 8.2.4 Make sure to uncheck the Multiline Data box if adding multiple values.
55
34.
35.
36.
37.
38.
39.
40.
41.
Fig 8.2.5 Entering the boolean values into a Post-it Panel allows us to visualize the Cull Pattern
without having to open the Boolean Collection Manager.
42.
43.
44.
45.
56
46.
Connect the W-output from the Weave component to the V-input of the Polyline component
Note: Now, youll probably notice that the truss is nearly complete but not quite, because the
upper chord extends beyond the first and last nodal point on our truss. We need to create a new
upper chord line that is only drawn between the first and last point in our upper sets of points. Rightclick on the Move component and turn its Preview Off.
47.
48.
Curve/Spline/Polyline Drag and drop another Polyline component onto the canvas
Connect the L-output from the second Cull Pattern component (again, these are the upper set of
points) to the V-input of this new Polyline component
Fig 8.2.6 The final truss definition shows how the Weave component helps organize the nodal points for the
interior diagonals so we can use a single polyline component to generate all of the interior chords.
Fig 8.3.1 We can use the Shift component to change the order of our point lists on two circles.
Now, lets begin by creating the definition from scratch:
1.
57
2.
3.
4.
5.
Curve/Primitive/Circle CNR - Drag and drop a Circle CNR (Center, Normal, and Radius) onto the
canvas
Right-click on the Circle-C input and click Set One Point
In the Rhino dialogue box, type "0,0,0" and hit enter
Right-click on the Circle-R input and Set Number to 10.0
Note: You could also connect a slider to the R-input of the Circle CNR component if youd like to
parametrically control this variable.
6.
7.
Vector/Constants/Unit Z - Drag and drop a Unit-Z vector component onto the canvas
Right-click on the F input of the Unit-Z component and Set Number to 10.0
Note: This Z vector will be used to define the height of our upper circle so if youd like to be able to
parametrically control this dimension, simply connect a numeric slider to the input of the Unit-Z
component.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
Curve/Division/Divide Curve - Drag and drop two Divide Curve components onto the canvas
Connect the Circle-C output to the C-input of the first Divide Curve component
Connect the Move-G output to the C-input of the second Divide Curve component
Params/Special/Slider - Drag and drop a numeric slider onto the canvas
Right-click on this slider and set the name to Crv Divisions
Double click on the Crv Divisions and set the following parameters:
Rounding Type: Integers
Lower Limit: 1.0
Upper Limit: 30.0
Current Value: 30.0
Connect the Crv Divisions slider to the N-input of both Divide Curve components
Note: You should now see 30 points evenly spaced along each circle.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
58
Logic/List/Shift List - Drag and drop a Shift List component onto the canvas
Connect the output of the second Divide Curve component to the Shift List-L input
Params/Special/Number Slider - Drag and drop another numeric slider onto the canvas
Right-click on this slider and set the name to Shift
Double click on the Shift slider and set the following parameters:
Rounding Type: Integers
Lower Limit: -10.0
Upper Limit: 10.0
Current Value: 5.0
Connect the Shift slider output to the S-input of the Shift List component
Params/Special/Boolean Toggle Drag and drop a Boolean Toggle onto the canvas
Right-click on the Boolean Toggle and set the name to Wrap
Double-click on the Wrap Toggle to change the value to True
Connect the Wrap Toggle component to the W-input of the Shift List component
Note: The Shift component moves the items in a list up or down a number of increments depending
on the value of the shift offset. If we set the slider to -1, then all items in the list will move down by
one entry number. Likewise, if we change the slider value to +1, all values of the list will move up by
one entry number. If the Wrap value equals True, then items that fall off the ends are re-appended.
In this example, we have a shift offset value set to +5, so that our list moves up by five entry number.
Now, we have a decision to make on how we would like to treat those first five values. If we set the
Wrap value to False, the first five values will be shifted up and out of the list, essentially removing this
value from the data set. This would result in a data matching problem because our two lists (the
points on the lower and upper circles) would have an unequal number of items. However, if we set
the wrap value to True, the first five entries will be moved back to the bottom of the list keeping the
list length the same in both lists.
28.
29.
30.
Fig 8.3.1 The final definition of the shifted circle tutorials can be seen above. What are some other ways you
may extend this definition?
59
Fig 8.4.1 Floating point numbers above five digits (like 123,456) are displayed in scientific notation.
For those of us that dont use scientific notation on a regular basis, it may be important to be able to reformat this data into a more reasonable notation. Go ahead and drag a single variable function
(Logic/Script/F1) onto your canvas and open up the Expression Editor (right-click on the F-input node). In
the expression dialogue box, type in the following: Format({0},x)
That probably doesnt make much sense to you, yet, so lets break that statement down step by step. The
first thing that we come across is the word Format. This is just a signature that tells Grasshopper that you
are going to be formatting an incoming variable into some other type of arrangement. There are a whole
bunch of other signatures that we can use in the expression dialogue box. To see the entire list of possible
functions, click on the box on the right side of the expression editor that says Display Function List. The
next thing we encounter in the statement is a left (or open) parenthesis. This just tells Grasshopper that
everything inside of these parentheses is what we intend to format. Moving right along, we next encounter a
quotation mark. This marks the beginning of the format string; or the instructions that tell Grasshopper how
we want to format our data. Next up, we see a left (or leading) curly brace followed by a zero and finally a
right (or trailing) curly brace. The value inside these curly braces is the format parameter. The format
parameter consists of zero or more runs of text intermixed with zero or more indexed placeholders, called
format items that correspond to an object in the parameter list of this method. The formatting process
replaces each format item with the string representation of the corresponding object. A zero indicates that it
will it will be replaced by the first variable in the parameter list. If we had two variables then our parameter list
would contain x and y. This means that we would also need to specify two format parameters (0 and 1
inside the curly braces) to be replaced with the incoming x and y variables. The next thing we come across
in the statement is a closing quotation mark which indicates the end of our formatting instructions. Following
the quotation mark, we see a comma which indicates the break between the format string and the format
parameter list. The next item after the comma indicates the first item in our parameter list. In this example,
we only have one variable (x) which contains the number 123,456. We could have renamed the x-variable to
any other name we would have liked (just right-click on the x-input node) but for now x is the variable
name. So, x will be the first variable in our parameter list. Finally, we close the Format function with the right
(or close) parenthesis.
Whew that is a lot to take in. But, lets take a look at whats happened to our original number
1.234560E+005. We re-formatted the number to return 123456.
But, what if we had wanted the formatted number to have exactly two decimal places of precision?
Remember that the value inside the curly brace is the format parameter which defines the formatting
instructions. So, lets type in the following statement into the expression editor: Format({0:0.00},x)
Notice, that the only difference in this statement is that we have added an argument which defines how we
want to format the data. In this case, we have added a colon after the index placeholder and then specified
the format instructions. So, when you see the string {0:0.00}; the first zero is the index place holder and the
value after the colon indicates how wed like to convert the number. Since this has been defined as 0.00 our
formatted number will have two decimal places. If we had wanted exactly five decimals; we could have used
the following format parameter: {0:0.00000}.
60
There are also a lot of other standard formatting methods by which to convert your variable data into another
useable format such as: numbers, currency, percentages, strings, hexadecimal values, etc. Below are a few
examples of these conversions.
Fig 8.4.2 The numeric N specifier format converts a number to a string of the form "-d,ddd,ddd.ddd",
where "-" indicates a negative number symbol if required, "d" indicates a digit (0-9), "," indicates a group
separator, and "." indicates a decimal point symbol. A precision specifier can be used to indicate the number
of decimal places you would like to include in your formatted text string. For example, the parameter {0:N4}
would return a number with exactly 4 decimal places.
Fig 8.4.3 - The "C" (or currency) format specifier converts a number to a string that represents a currency
amount. The precision specifier (the number that can be used after the C specifier) indicates the desired
number of decimal places in the result string. If the precision specifier is omitted, the default precision is
defined by the settings in the Regional and Language Options in Control Panel. These Regional and
Language Options will also affect which currency symbol is used. If no language setting is specified (cultural
invariant) then a default symbol will be used.
Fig 8.4.4 - The "P" (or percentage) format specifier multiplies a number by 100 and converts it to a string that
represents a percentage. The precision specifier (optional) indicates the desired number of decimal places.
Fig 8.4.5 This example uses the variable as part of a formatted text string. This method, in particular, can be
very helpful in creating custom labels for objects in your scene or for creating customized data analysis (like
floor area calculations) for specific output options (as well see in the next tutorial).
61
Fig 8.4.6 A hexadecimal is a numeral system which uses sixteen distinct symbols, most often the symbols 0
9 to represent values zero to nine, and A, B, C, D, E, F (these can also be lowercase) to represent values ten
to fifteen. The hexadecimal ("X") format specifier converts a number to a string of hexadecimal digits. The
case of the format specifier indicates whether to use uppercase or lowercase characters for hexadecimal
digits that are greater than 9.
Params/Special/Read File Drag and drop a Read File component onto the canvas
Params/Special/Post-It Panel Drag and drop a Post-it Panel onto the canvas
Double-click on the Post-it Panel and type in the location of your textfile: C:\Tutorials\point_list.txt
Connect the Post-it Panel output to the P-input of the Read File component
Note: Almost immediately, your Read File component should turn from orange to grey. If it has
turned red, double check to make sure you typed in the location of the text file in correctly.
5. Params/Special/Post-It Panel Drag and drop a Post-it Panel onto the canvas
6. Connect the C-output of the Read File component to the input of the Post-it Panel
7. Params/Geometry/Point Drag and drop a Point parameter component onto the canvas
62
8. Connect the C-output of the Read File component to the input of the Point parameter component
Note: You should now see the point coordinates that we typed into the .txt file displayed in the Postit Panel. We have also fed this information directly into a Point parameter component which has
generated 6 points at the coordinates we specified. If we change any of the original .txt values (in
the text editor) and re-save the .txt file, the Read File component will automatically update the values
of both the Post-it Panel and the 3d points.
Fig 8.5.1 The Read File component imports a data file from a specific directory on your computer.
In this example we have imported a set of coordinates from an external textfile.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
Surface/Freeform/Planar Surface Drag and drop a Planar Surface component onto the canvas
Connect the P-output of the Polygon component to the E-input of the Planar Surface component
Surface/Analysis/Brep Area Drag and drop a Brep Area component onto the canvas
Connect the S-output of the Planar Surface component to the B-input of the Brep Area component
Note: The Brep Area component has analyzed the area of each of our floor plates. Now, that we
have the area of each floor plate, we need to also create a series of numbers to keep track of the
index number of each floor plate in our scene. With those two variables, we can create a text string
in the form of Floor X Area = YYYY.YY sqft where X is the floor plate index number and Y is the
floor area rounded to two decimal places of precision.
23. Logic/Sets/Series Drag and drop a Series component onto the canvas
24. Connect the L-output of the List Length component to the C-input of the Series component
63
25.
26.
27.
28.
29.
30.
31.
32.
33.
Right-click on the S-input of the Series component and Set the Number to 1.0
Logic/Script/F2 Drag and drop a two variable expression onto the canvas
Connect the S-output of the Series component to the x-input of the two variable expression
Connect the A-output of the Brep Area component to the y-input of the two variable expression
Right-click on the y-input of the two variable expression and toggle the Flatten parameter
Right-click on the F-input of the two variable expression and open up the Expression Editor
In the expression dialogue box type in the following: Format("Floor {0} Area = {1:0.00} sqft",x,y)
Params/Special/Post-it Panel Drag and drop a Post-it Panel onto the canvas
Connect the r-output of the two variable expression to the input of the Post-it panel to see the
formatted text string
34. Right-click on the Post-it Panel and select Stream Contents
35. When prompted, select a location on your hard drive to save the contents of the Post-it Panel. I
would recommend using the same directory as the original point_list.txt file.
36. Save this file as C:\Tutorials\floor_area.txt (the .csv extension can also be a very useful file format)
37. Note: Streaming Contents of a Post-it Panel is the easiest way to export data to a common file
format (.txt, .csv) to be manipulated in another software program. Be aware that the textfile will be
overwritten whenever the Panel content updates. You should not open these textfiles in applications
which set read only attributes while the source Panel is still active. Lets finish of this tutorial by
adding labels and extruding our floor plates.
38. Just for fun, go ahead and open up the floor_area.txt file and make sure the contents of the Post-it
panel have exported properly.
39. Vector/Point/Text Tag Drag and drop a Text Tag component onto the canvas
40. Connect the C-output of the Brep Area component onto the L-input of the Text Tag component
41. Connect the r-output of the two variable expression to the T-input of the Text Tag component
Note: You should now see a series of little strings drawn in the viewport as feedback items. Text and
location are specified as input parameters. When text tags are baked they turn into Annotation Text
Dots.
42.
43.
44.
45.
46.
47.
Fig 8.5.2 Heres a look at the final definition for reading and writing data in Grasshopper.
64
8.5.3 A closer look at the end of this definition shows the formatted text strings which can be streamed
directly to a .txt or .csv file.
Fig 8.5.4 Here we see the 6 polygonal floor plates located at the centroid points that were imported into
Grasshopper through the Read File component. Text Tags have been added to show the floor areas at each
floor.
65
Data Trees
The Post-it Panel holds the actual data items (in this case, it is the numbers 1.0, 2.0, 3.0, 4.0, and 5.0) in our
list. But, there is also data path which locates that list of data inside a larger system. In this simple example,
we only have one path in our tree, thus our list of five numbers makes up the entire data tree. We can use a
Param Viewer (Params/Special/Param Viewer) to look at data structure in this example. By double clicking
on the Param Viewer, we can toggle between the graphical version of our data tree and a textual
representation. Since, our structure only has one path we would call this a Flattened Tree (well cover more
on this in a minute). But, what if we wanted to count the number of fingers on both hands?
This time, well connect two Post-it Panels (see next page) into the C-input of the Series component one
defining the number of fingers on our left hand and the other defines the number on our right hand.
Because we can store lists inside a larger data structure (the tree), we now have two paths each containing
five data elements (each of our fingers). The first path {0;0} indicates the list of elements that were created
when we connected the first Post-it Panel to the C-input of the Series component. Since, I connected Left
Hand Panel first; the initial path will correspond to the list of values associated with our left hand. Next, I
connected the Right Hand Panel to the C-input of the Series component; so the next path in our structure
indicates the values on our right hand. We see from the Param Viewer that both paths contain five items
(N=5).
66
Fig 9.1.1 By connecting two unique feeds to the C-input of the Series component, the output data tree will
have exactly two branches.
The great thing about data trees is that they allow us the ability to keep our original lists intact while still
maintaining some edit ability with regards to the location of each of the branches. In the example above,
each of the lists of numbers are stored on its own branch. This structure provides easy access to individual
branches and individual data items. We can isolate all of the numbers on our right hand by extracting all of
the data items on path {0;1}. In older versions there were no branches (or more appropriately, there was
only one branch) so all items were stored in one list. Thus, it would have been more difficult to isolate the
five numbers associated with our right hand. Essentially, we would have had to isolate data items 5 through
9 (in a flattened structure, our list would contain ten items). This may not be difficult on such a simple
example, but keeping track of particular items in a much more complicated definition can provide many
problems. Data trees will have a profound impact on how we structure our definitions from here on out.
Its helpful to picture a data tree like a real tree. The image on the facing page (created by David Rutten)
represents a reasonably complex, yet well structured data path diagram.
In this example, there is a single master branch (you could call this the trunk, but since it's possible to have
multiple master branches, it might be a bit of a misnomer) at path {0}. This path contains no data, but does
have 3 sub-branches. Each of these sub-branches inherits the index of the parent branch {0} and adds their
own sub-index (0, 1 and 2 respectively). Each of these sub-branches are again host to 2 sub-sub-branches
and they again contain no data themselves. Once we reach nesting level 4, we finally encounter some data
(the one dimensional arrays that are stored at the 4th level of this data structure are represented as colorful
thick lines where each data item in that array is shown as a bright circle). Every sub-sub-sub-branch (or level
4 branch) is a terminus branch, meaning they don't subdivide any further. Each data item is thus part of one
(and only one) array that forms the branches of the data tree, while each branch array has a path that
specifies its location within the tree.
67
Fig 9.1.2 The Grasshopper Data Tree and the Param Viewer. Image courtesy of David Rutten.
To further examine data tree structures, let's take a look at a very simple example. Lets start by creating two
curves in Rhino which we will reference into Grasshopper using the Curve parameter object
(Params/Geometry/Curve). Now drag and drop a single Divide Curve component (Curve/Division/Divide
Curve) onto the canvas. Well use this component to divide both curves into 20 individual segments ultimately giving us 21 points on each curve. Feed all of the points from the P-output of the Divide Curve
component into the V-input of a Polyline component (Curve/Spline/Polyline). This will create a new line
through each of the division points.
68
Fig 9.1.3 A Grasshopper diagram showing the two referenced curves and the resulting division points
created by the Divide Curve component.
If we had been using a version of Grasshopper prior to the release of 0.6.00xx the Polyline curve would have
created only one polyline through our entire point list of 42 points which have been stored in a flattened
array with no branches or paths. The resulting curve and point index would have looked like following:
Fig 9.1.4 The Param Viewer (Params/Special/Param Viewer) shows us that the flattened array has 1 path with
42 items in the list.
69
However, we now know that Grasshopper has the capability to incorporate paths and branches, so we can
use that data structure to control how the Polyline component behaves. If we follow the exact same steps as
before, only this time using Grasshopper version 0.6.0000 or higher, our Polyline component would create
two polylines because the point data from the Divide Curve component has been stored in a data tree
structure.
Lets break this down a little further. Each curve was divided into 20 segments (again, giving us 21 points on
each curve) so Grasshopper stored the 21 points on the first curve at path {0:0} and stored the 21 points
from the second curve at path {0:1}. We can check out the tree structure by connecting the Param Viewer
(Params/Special/Param Viewer) to the P-output of the Divide Curve component. The Param Viewer shows
us that our data structure has 2 paths (0:0) and (0:1) which each contain a list of 21 items. Youll notice that
now our Polyline component has created two unique polylines because the point list being fed into the
Polyline component contains two paths. The point index of the Divide Curve component and the resultant
polylines should now look like this:
Fig 9.1.5 Notice that because our data structure has two paths; the Polyline component will create two
unique curves.
Now, you may be hearing yourself say, This sounds great and all but this data tree stuff has really
complicated everything. How am I supposed to go into this so called data tree and select an item out of
my list I was completely happy with version 0.5 when everything was stored in a single list and all I had to
do was specify a particular index number and be done with it
Fair enough. Lists are much easier to deal with because we can access the data with a single index number.
Sometimes it is easier to just flatten your data structure so that you can access an individual item.
Fortunately for us, there are two ways to do this. The first would be to use a Flatten component found under
the Logic tab (Logic/Tree/Flatten). We can feed any data structure into the Flatten component and it will in
turn collapse the tree structure into a one dimensional array. This method works well, but sometimes
(particularly if you are working on a very large definition) you may want to try and save your screen real
estate by trying to use as few components as possible. Well, we can also flatten a data structure by right-
70
clicking on the input node of component and selecting the flatten check box found in the drop down menu.
Either way will work just fine.
Fig 9.1.6 There are two methods available for flattening a data structure. Notice that the Param Viewer
shows that our data structure now has only one path with 42 items (much like it did in the older versions of
Grasshopper).
Its easy enough to retrieve an item out of a flattened list by simply specifying the index number in a List Item
component (Logic/List/List Item). However, the process becomes just a bit more involved when working
with a data tree like the one above; where we have 2 paths with 21 items on each path. Lets say we are
interested in looking at an individual point in our data structure say point 3 (index number 3 in our list) on
path {0:1} (which corresponds to Curve 2 in our definition).
First, well need to determine which path our point falls on. We know from our Param Viewer that our point
falls on path {0:1} but we need a way of extracting that information so that we dont have to manually type in
0:1. I know thats not very hard to do, but if your tree had 500 branches then managing your path structure
becomes much more complicated. So, lets begin by connecting a Data Path parameter object
(Params/Primitive/Data Path) to the output-node of the Param Viewer. If you were to connect a Post-it
Panel (Params/Special/Panel), you would see that this simply creates a list of all of the data paths in your
structure. Now we just need to go into that list and specify which item (or path) we want to use.
71
Fig 9.1.7 If we are interested in extracting an individual item from a data tree, we need to be able to specify
the Data Path and the Item index number.
Click on the Logic tab and drag a List Item (Logic/List/List Item) component onto the canvas. Connect the
P-output from the Divide Curve component to the L-input of the List Item component. Now, drag a number
slider onto the canvas (Params/Special/Number Slider). Well use this slider to specify which item we want
to retrieve from our list. Double-click on this slider and change the rounding type to Integers. The other
default values for this slider are just fine for this example. Now, connect this slider to the i-input of the List
Item component.
Fig 9.1.8 We can use a List item component to retrieve a specific Data Path.
We can easily change which path we want to look at by simply changing the sliders value. Its probably a
good idea to label this slider path so we keep our definition organized. Now, that we have specified the
path we want to look at; we have two options to retrieve data items from the array at that data path location.
We can use a Tree Branch (Logic/Tree/Tree Branch) component to retrieve all of the items on a specific
path. If we use a Tree Branch component in this example, we would isolate all 21 points from either path we
specify with the slider.
However, if we are more interested in isolating an individual item from a data tree; we will want to use a Tree
Item (Logic/Tree/Tree Item) component instead. Connect the P-output from the Divide Curve component to
the T-input of the Tree Item component. Now, connect the output node from the List Item component (which
has isolated our path location) to the P-input of the Tree Item component. Drag and drop a new slider
72
(Params/Special/Number Slider) onto the canvas and rename this item. Well use this slider to specify
the index number in the array we are looking at. Double-click this slider and change the rounding type to
Integers and set the length to 21 since we have twenty one points in each array. Connect this slider to the iinput of the Tree Item component. Now we can easily isolate a particular data path and a specific item in that
array by changing either of the two sliders in our definition.
Fig 9.1.9 We now have a slider which will retrieve our data path and another slider which isolates a specific
index number within that array.
Fig 9.2.1 A flattened list shows one path with 100 items; whereas a grafted list returns 100 paths each with
one item on each path.
73
The Flatten and Graft components are very useful tools but they beg the question how can we create a
unique data structure perhaps one that has 4 paths with 25 items on each path. With the help of a few
new data tree components, well quickly be able to manipulate our data sets.
This next tutorial is one of my favorites, not only because it will help us understand how to construct a unique
data tree from a flattened structure, but also because its can also be used in a lot of different applications.
Conceptually, it is based on the Blend tool in Adobe Illustrator which creates a series of blended sub-curves
between any two outer curves you specify. The default setting in Adobe Illustrator is to evenly space the
sub-curves (a linear interpolation) but well use a Graph Mapper to control the falloff between the two outer
curves.
74
Fig 9.2.2 At this point, we have simply referenced in two curves from Rhino and subdivided each curve
into 50 different segments
17. Curve/Primitive/Line Drag and drop a Line component onto the canvas
18. Connect the P-output of the first Divide Curve component to the A-input of the Line component
19. Connect the P-output of the second Divide Curve component to the B-input of the Line component
Note: You should now see a series of lines connecting your two referenced curves. Were going to use
an Evaluate Length component to subdivide these new lines according to the curve distribution set by
the Graph Mapper.
20. Logic/Sets/Range Drag and drop a Range component onto the canvas
21. Params/Special/Number Slider Drag and drop a Numeric Slider onto the canvas
22. Right-click on this slider and set its name to Blend Subdivisions
75
23. Double click on the Number Slider and set the following:
Rounding: Integers
Lower Limit: 0.0
Upper Limit: 100.0
Current Value: 10.0
24. Connect the Blend Subdivisions slider to the N-input of the Range component
Note: Remembering our previous discussion on Ranges, we have just created a list of 11 numbers that
are evenly divided between 0 and 1 (the default setting for the interval domain). We can use the Evaluate
Curve component to evaluate a curve at a certain factor along its length. Length factors can be supplied
both in curve units and normalized units. Since we dont know how long each of our curves will be, its
best if we use these values as normalized units; meaning the start of the curve will always be position 0.0
and the end will always be position 1.0 regardless of the length of the curve. Thus, if our list has 11
values (all evenly divided between 0 and 1) then our evaluated curve will look like the image below.
Fig 9.2.3 The Evaluate Length component will evaluate a curve at certain factors along its length. This
curve is using Normalized Units as its evaluation criteria.
25.
26.
27.
28.
76
Params/Special/Graph Mapper Drag and drop a Graph Mapper onto the canvas
Connect the R-output of the Range component to the input of the Graph Mapper
Right-click on the Graph Mapper and set the graph type to Bezier
Change the Bezier handles to adjust the different values in the list (this will become more visually
apparent once we connect the Graph Mapper to the Evaluate Length component)
Fig 9.2.4 We can use the Graph Mapper to re-map the linear distribution of a Range component. This
list can be used to seed many different components, but well use them as the Normalized Units for the
Evaluate Length component.
Fig 9.2.5 At this point, your definition should look similar to the image above.
29. Params/Special/Param Viewer Drag and drop a Param Viewer onto the canvas
30. Connect the L-output of the Line component to the input side of the Param Viewer
Note: Youll notice that our data tree has one path with 51 data items. Ideally, we want to evaluate every
line in our list at each of the normalized points defined by the Graph Mapper. In order to achieve this
result, we need to create a new path for each line in our list so that every path gets evaluated for each of
the Bezier points. We can use the Graft component to create a new branch for each data item in our list.
31. Logic/Tree/Graft Tree Drag and drop a Graft Tree component onto the canvas
32. Connect the L-output of the Line component to the D-input of the Graft component
33. Params/Special/Param Viewer Drag and drop a Param Viewer onto the canvas
77
34. Connect the T-output of the Graft component to the input side of the Param Viewer
Fig 9.2.6 Notice that the Graft component has created a new branch for every data item in our tree.
35. Curve/Analysis/Evaluate Length Drag and drop an Evaluate Length component onto the canvas
36. Connect the T-output from the Graft component to the C-input of the Evaluate Length component
37. Connect the output node of the Graph Mapper component to the L-input of the Evaluate Length
component
38. Params/Special/Param Viewer Drag and drop another Param Viewer onto the canvas
39. Connect the P-output to the input side of the Param Viewer
Note: We have now evaluated every line in our list (each path) at each of the 10 points being output from
the Graph Mapper. You should see a series of points that are distributed along each line at varying
intervals. Try changing the Bezier handles again to get an idea how this graph effects our points. Youll
also notice that our data tree has changed again. Before the Evaluate Length component was added,
our tree had 51 paths each with one item per branch. However, the Param Viewer downstream of the
Evaluate Length component shows that we still have 51 paths, only this time each branch contains 11
data items. These are the 11 points on each of our lines. Remember, our end goal is to draw a bunch of
lines that are perpendicular to the direction of the Line component (see step 17). If we were to feed the
points coming out of the Evaluate Length component into an Interpolated Curve component we would
create 51 curves (each passing through the 11 points on each branch). Yet, these 11 points on each
path are running in the same direction as the Line component. We need to flip our data tree so that
instead of a tree structure that contains 51 paths with 11 items per branch we get 11 paths each with
51 items per branch. Take a minute to let that sink in. By flipping the data tree, we can change the order
or our points, and ultimately the direction of our interpolated curves. Well need to use the Path Mapper
component in order to change the direction of our data structure.
78
Fig 9.2.7 Our data tree now contains 51 paths each with 11 items per branch.
48. Logic/Tree/Path Mapper Drag and drop a Path Mapper component onto the canvas
49. Double click on the Path Mapper to open up the Lexical Combo Editor
Note: There are two sides that have to be completed in order for the Path Mapper to work properly. The
left hand side of the component is called the Source Mask. The right side is referred to as the Target
Mask. I will explain more about what these two terms mean in just a minute, but for now enter in the
following data exactly as it is written.
50.
51.
52.
53.
79
Fig 9.2.8 The end of our definition shows that we have flipped our data tree so that we now have 11 paths
each containing 51 data items per branch.
Fig 9.2.9 A zoomed out view shows the final definition from start to finish
Lets take a more in depth look at the Path Mapper component. Lexical operations are logical mappings
between data paths and indices which are defined by textual masks and patterns. For example, you could
define a lexical rule like "Take the original path but ignore the last index" using the English language. This
would be very readable to human beings, but not so for computers. Since we're the intelligent ones, it's only
fair that we adapt.
80
Furthermore, whether or not a Lexical Mask is considered valid depends on where it is used. If the mask is
used to create a lexical pattern, (i.e. a source mask), you are only allowed to use placeholders for path and
item indices. If however, the mask is used to mutate a lexical pattern, (i.e. a target mask) then every element
can be written in the form of a constant number, a placeholder or an expression.
The following are all valid source masks:
Valid Source Masks
{A}(i)
{A;B}(i)
{first;second}(index)
In the table above, "A", "B", "i", "first", "second" and "index" are all placeholders. Placeholders are names we
define when writing the pattern. Placeholder names must adhere to the same rules as variable names in
Grasshopper expressions. The Source Mask should adhere to the same syntax as the incoming data. For
example, lets say the incoming data source has two paths (each three levels deep) and each path contains
five items. The paths in our tree would read {0;0;0} and {0;0;1} and {0;0;2}. Each path is three levels deep.
Thus, the path segment in our Source Mask also has to be three levels deep, only we have to use
placeholders. A proper path segment for our Source Mask would read {A;B;C}. Since, the rules state that
the item segment can only contain exactly one item, we usually use the placeholder (i). Thus, a valid Source
Mask for this example would read: {A;B;C}(i).
Invalid Source Masks
{}(i)
{A;}(i)
{first;second}
The first mask is invalid because it does not define any path elements, the second mask is invalid because it
has a rogue semi-colon and the third mask is invalid because it lacks an item element.
Target Masks are more flexible, since they are evaluated rather than declarative. Given the above three valid
Source Masks, these would all be valid Target Masks:
Target Masks
{0}(i)
{i}(B)
{10*first+second}(index)
81
When used in conjunction, the first Source and the first Target mask will effectively flatten an entire data tree
into a single branch with path {0}. But since it maintains item indices ("(i)" is the item segment in both the
Source and the Target), it will overwrite the items in the first branch with the items in the second branch
which happen to have the same index.
The second Source and Target masks combine two operations, namely stripping the first part of the path ("A"
is not present in the Target mask, thus it disappears), and inverting the item and path indices. This mask
combination will 'flip' a data matrix along the diagonal. This is the Source and Target masks that we used in
the blended subdivisions tutorial.
There are additional placeholders available for target masks which allow you to track your overall progress in
the data tree iteration. The "path_index" placeholder is an integer which is incremented for every new data
tree branch that gets loaded. For example the "{path_index}(i)" target mask would simplify all branches in
the entire tree, while keeping all branches separate. The "path_count" placeholder represents the total
number of branches in the current tree. The "item_count" placeholder represents the total number of items in
the current branch.
82
10 Vectors
10.1 Vector Basics
Before we jump into the nuances of vector algebra, it should be noted that much of the content for this
chapter has been referenced from Rajaa Issas publication, Essential Mathematics for Computer Graphics.
For a free download or if you would like to purchase the original publication, please visit:
http://www.lulu.com/product/download/essential-mathematics-for-computational-design/6470006.
I often hear the question, What are vectors good for? Its a good question, because its one of the more
difficult topics to teach since vectors are inherently defined as abstract information. What do I mean by
abstract information? Well, Vectors in 2D coordinate systems are represented with two real numbers in the
form:
V = <a1, a2>
Similarly, in 3-D coordinate system, vectors are represented by three real numbers and would look like:
V = <a1, a2, a3>
You probably noticed that vectors look almost identical to points. Lets take a quick look at points. A point is
a location in space. A point does not have any size. Its only property is a location which is defined by three
numbers: (x-coordinate, y-coordinate, z-coordinate). In Cartesian space there is an origin point (usually at
(0,0,0)) and all other points are located somewhere relative to that location. Thus, if we say that there is a
point at coordinates (3,1,5) then we know that point is located three units to the right of the origin on the Xaxis (usually positive coordinates are to the right of the origin and negative coordinates are located to the
left) then one unit to the right of the origin on the Y-axis, and then five units up from the origin in the Z-axis.
Vectors differ from points in that their parameters are defined by a distance as opposed to a location. A
vector may be defined as (delta-x, delta-y, delta-z) where the delta values are the component distances from
two points in space. Vectors can exist anywhere in space because they are abstract and are not tied to a
location until they have been anchored to some point. Once anchored to a point, Vectors can be visualized
(typically done with arrows) by using the Vector Display component (Vector/Vector/Display).
For example, if we have a vector that has a direction parallel to the x-axis of a given 3-D coordinate system
and a magnitude equal to 5.18 units, then we can write the vector as follows:
V = <5.18, 0, 0>
Note: Angle brackets distinguish a vector from point coordinates which use parenthesis.
To represent that vector, we need an anchor point in the coordinate system. For example, all of the red line
segments in Fig 10.1.1 are equal representations of the same vector.
The Grasshopper definition on the following page is set up as such:
83
Fig 10.1.1 We can visualize any defined vectors by using the Vector Display component.
Fig 10.2.1 Vectors between two points are defined by three distance values (delta-x, delta-y, delta-z).
84
Fig 10.2.2 - The following definition displays this vector using the Grasshopper Vector Display component,
and marks the end of the displayed vector that coincides with point B.
85
Fig 10.3.1 Notice that the position vector components are the same as the coordinates of Point B.
86
The resulting vector is the same of that resulting from using Grasshopper's built-in addition component:
Fig 10.4.2 Add two vectors together by adding their corresponding components.
Vector addition is also useful for finding the average direction of multiple vectors. In this case, we usually use
same-length vectors. Here is an example that shows the resulting vector addition between two same-length
vectors:
Fig 10.4.3 We can find the average between two same-length vectors by adding the vectors together.
This same principle can be applied to vectors of different length. Take for example the following example:
87
Fig 10.4.4 Here we have used the Vector Multiply component (Vector/Vector/Multiply) to scale our Y unit
vector by two. We will cover vector multiplication later in this chapter.
Fig 10.5.1 The average direction can be found by adding two unit vectors.
88
Note that Grasshopper vector component has an output L that is the vector magnitude:
89
Grasshopper has built-in vector dot product component as shown in the following illustration:
When calculating the dot product of two unit vectors, result is always between -1 and +1. If two unit vectors
are perpendicular to one another, the dot product will result in a value of 0. Conversely, parallel unit vectors
will yield a dot product of either +1 or -1 depending on the direction of each vector. The vector dot product
component has a U input which allows us to unitize the input vectors.
The following definition shows both conditions (perpendicular and parallel):
Fig 10.7.1 We can use the vector dot product to determine if two unit vectors are perpendicular or parallel to
one another.
90
Heres another property of vector dot products. The dot product of a vector with itself is that vector length
raised to the power of two:
a.a = |a|2
And here is the mathematical proof of that same formula:
If vector a = <a1, a2, a3> then from the definition of dot product of two vectors:
a.a = a1*a1 + a2*a2 +a3*a3
or
There is also a nice geometric interpretation to the dot product. There is an important theorem that states:
a.b = |a||b|cos(), or
cos() = a.b / (|a||b|)
And if vectors a and b are unit vectors, we can simply say:
cos() = a.b
Therefore, we can use the vector dot product to find the angle (theta) between two unit vectors.
91
The following definition proves that the cosine of theta equals the dot product of two unit vectors:
We can find the angle between two vectors by using the Vector Angle component (Vector/Vector/Angle).
In the most practical way, you can think of the dot product of two vectors to be the projection length of one
vector on the other. The best way to understand projections is to see a couple of sketches.
Fig 10.7.2 The two sketches above show the projection of vector b onto vector a.
92
Fig 10.7.3 The diagram above illustrates that the projection distance of vector b onto vector a is exactly
0.707 units of the original unit vector (of length 1.0).
93
Given:
Vector a = <a1, a2, a3>
Vector b = <b1, b2, b3>
The cross product a X b is solved used determinants. Here is a quick illustration of how to calculate a
determinate mathematically:
This example finds the vector cross product using the built-in component:
94
Below is an example on how to calculate the length of the vector cross product using the built in component.
And here is the same example using a three variable expression to solve for the vector cross product length:
95
In determining the cross product, the order of operation is important. For example:
If we have two points:
a = (1, 0, 0)
b = (0, 1, 0)
Then:
a x b = (0, 0, 1)
b x a = (0, 0, -1)
In Rhino's right-handed system, a X b is defined as a vector c that is perpendicular to both a and b, with a
direction given by the right-hand rule (where a = index finger, b = middle finger, and result = thumb).
96
In the following figure, given points a and b, find point p. Notice that:
A is the position vector for point a
B is the position vector for point b
V is the vector going from a to b
From vector addition property:
A + V = B, or
V=B-A
However, the line equation is:
P = A + t*V,
and since t=0.5 and V=B-A (from the above), then we can say:
P = A + 0.5(B-A)
Use the above equation to create the Grasshopper definition seen below:
97