Skip to main content

Tutorial - Integrate Rhino/Grasshopper

note

Estimated time: 45 minutes
Difficulty level: Intermediate

Introduction

Welcome to this tutorial on integrating Grasshopper with VIKTOR! In this tutorial, you will learn how to create a VIKTOR web app with a Grasshopper model running behind it by the following steps:

  1. Setup a folder locally and test
  2. Setup the worker
  3. Build the VIKTOR app
  4. Use your own Grasshopper model

By the end of this tutorial, you will have created a simple VIKTOR application that creates a geometry and data view of a simple box, see the image below:

So, let's get started and learn how to create a VIKTOR app based on a Grasshopper model!

Pre-requisites

Prerequisites

Explanation of setup

Before diving into the steps, let's explain how the integration will work. See the following diagram:

The following will happen:

  1. The user fills in input parameters in the VIKTOR UI
  2. In VIKTOR app.py these input parameters will be saved in the input.json file, and sent to the worker.
  3. The Generic worker will run Rhino/Grasshopper (on your local machine), based on a Grasshopper script (sample_box_grasshopper.gh) and the input parameters (input.json).
  4. The Grasshopper model generates a 3D file (geometry.3dm), which is sent back by the worker.
  5. In VIKTOR app.py, the 3dm geometry file will be sent back to the VIKTOR UI.

Now let's setup everything to get this running! We will go through the diagram from right to left.

1. Setup a folder locally and test

Install Hops

Hops is a plugin for Grasshopper, which will be used to make it possible to call the Grasshopper script externally, using a local Rhino Compute server.

  1. Install Hops via the Package Manager in Rhino (type PackageManager on the Rhino command line and search for "Hops")

  1. Make sure Rhino Compute will be launched at start up. In Grasshopper, go to File -> Preferences and check the following settings:

We recommend to uncheck Hide Rhino.Compute Console Window, because you can then easily see if Rhino Compute is running and debug when necessary.

The full documentation of Hops can be found in the Rhino documentation.

Create a folder where Rhino/Grasshopper runs

Create a folder where the Rhino/Grasshopper models will run. Make sure it is a location where you have access rights, for example: C:\Users\your-name\viktor-grasshopper.

Download the following zip file, unzip the folder and copy the 3 files to the folder you just created: files-grasshopper-tutorial.zip

Check the Rhino/Grasshopper model

Now open the Grasshopper file (sample_box_grasshopper.gh) with the Grasshopper plugin. This should lead to the following view:

Let's take some time to check out what is happening in the Grasshopper script:

  1. Three Hops input parameters (width, length and height) are defined based on the Get Number component of Hops.

  2. A simple box is created based on the width, length and height, which is subsequently meshed.

  3. The mesh is baked into Rhino using the Context Bake component of Hops.

If you change the input parameters, you will see that a box is drawn in Rhino. With this setup, we are ready to run this Grasshopper file from a Python script.

Test run_grasshopper.py

The VIKTOR worker will automatically run the Grasshopper file using the local Rhino Compute server, by the Python file (run_grasshopper.py) that you placed in the folder:

When you open the Python file with an IDE (for example Pycharm), you should see the following code:

# Pip install required packages
import os
import json
import compute_rhino3d.Grasshopper as gh
import compute_rhino3d.Util
import rhino3dm

# Set the compute_rhino3d.Util.url, default URL is http://localhost:6500/
compute_rhino3d.Util.url = 'http://localhost:6500/'

# Define path to local working directory
workdir = os.getcwd() + '\\'

# Read input parameters from JSON file
with open(workdir + 'input.json') as f:
input_params = json.load(f)

# Create the input DataTree
input_trees = []
for key, value in input_params.items():
tree = gh.DataTree(key)
tree.Append([{0}], [str(value)])
input_trees.append(tree)

# Evaluate the Grasshopper definition
output = gh.EvaluateDefinition(
workdir + 'sample_box_grasshopper.gh',
input_trees
)

# Create a new rhino3dm file and add resulting geometry to file
file = rhino3dm.File3dm()
output_geometry = output['values'][0]['InnerTree']['{0}'][0]['data']
obj = rhino3dm.CommonObject.Decode(json.loads(output_geometry))
file.Objects.AddMesh(obj)

# Save the rhino3dm file to your working directory
file.Write(workdir + 'geometry.3dm', 7)

As can be seen in the imports, two packages are necessary: rhino3dm and compute-rhino3d. These packages can be installed via pip:

  • pip install rhino3dm
  • pip install compute-rhino3d
Python version

Note that Rhino the highest Python version that Rhino supports is 3.10: we recommend to use a Python version between 3.7 and 3.10. Make sure that one of these Python versions is installed on the computer where you will run Rhino/Grasshopper.

Let's test if the Python file works:

  1. Make sure Rhino and Grasshopper are running, such that the local Rhino Compute server is also running. You don't have to open a Grasshopper file.
  2. Run the run_grasshopper.py from your IDE

You should now see that the following flow runs automatically: Rhino Compute is running with the input parameters read from input.json and the output file geometry.3dm is created in the same folder.

If this works correctly: great! Now you are ready for the next step.

2. Setup the worker

A worker is a program that connects VIKTOR with third-party software to execute tasks and retrieve results through the platform. In this case, the worker will start Rhino/Grasshopper with the input data and send the resulting geometry back.

Install worker

Follow these steps to install the worker:

  1. Go to your VIKTOR environment via the browser and log in:
  2. Create the worker in your VIKTOR environment

My Image

  • Step 1 Go to the "Workers" tab
  • Step 2 Click the "Create worker" button (top right)
  • Step 3 Fill in the description, allocation to specific and use your development workspace
  • Step 4 Click "Create". You will get the following pop-up (see figure below). Keep this window open, you will need the credentials in the next step.

  1. Download and install the Generic worker using this guide. Select the Generic integration. The installer starts an installation wizard from which the worker can be configured. Administrator rights on the machine are required to perform the installation.

  2. Specification of the installation directory. The standard directory that is used for the installation is:

C:\Program Files\VIKTOR\VIKTOR for <application> <software package> <version>
  1. Configuration of the worker. Using the installation wizard you will be asked to fill the required information step-by-step. During this installation wizard you are asked for the credentials you generated in step 1.

Setup worker

The setup of the worker is defined in the config.yaml file, which can be found in the same folder where the worker is installed (see last chapter). Open the config.yaml file (using for example Notepad) and replace the text with the following:

executables:
run_grasshopper:
path: 'C:\Users\your-name\AppData\Local\Programs\Python\Python310\python.exe'
arguments:
- 'C:\Users\your-name\viktor-grasshopper\run_grasshopper.py'
workingDirectoryPath: 'C:\Users\your-name\viktor-grasshopper'
maxParallelProcesses: 1 # must be 1
Set correct paths
  • Make sure to set the path correctly to the Python executable. Tip: search for python.exe in the Windows Search Bar and click Open file location. Note: the highest supported Python version is 3.10.
  • Make sure to set the arguments correctly to the run_grasshopper.py file.
  • Make sure to set the workingDirectoryPath correctly to the folder you created in step 1.

Save the file when you have defined the paths correctly.

Start up worker

Once you have saved your config.yaml file, you can run viktor-worker-generic.exe. Be sure to run the executable with Administrator rights. If all went well, you will be presented with the worker terminal in which the message: "Successfully connected to the server" is displayed. Also in in top right corner in your viktor environment you should see a green indicator in your worker overview, see the figure below.

Nice work! The integration is ready to use, let's setup the VIKTOR app.

3. Build the VIKTOR app

Create an empty app

Let’s first create and start an empty app. If you don't remember how this worked you can check out the first few steps of the Create your first app tutorial. Make sure to give your app a recognisable name, like "my-grasshopper-app".

Here a short summary of the process.

# Create an empty editor-type app
> viktor-cli create-app my-grasshopper-app --app-type editor
# Navigate to the app directory and install the app
> cd my-grasshopper-app
> viktor-cli install
# Clear your database just to be sure
> viktor-cli clear
# And start the app!
> viktor-cli start
caution

Please be aware that the create-app function sets the newly created app to use the latest SDK-version. This tutorial requires an SDK version of at least 14.4.0.

Open your app in your browser by visiting the URL shown in the command-line shell:

Add input fields

We will add 3 input fields to our app: width, length and height. We will use Numberfield for this.

  1. Open app.py, and add the relevant fields to your parametrization. Don't forget to import the necessary fields. In the end your app.py file should look like this:
from viktor import ViktorController
from viktor.parametrization import ViktorParametrization
from viktor.parametrization import NumberField
from viktor.parametrization import Text

class Parametrization(ViktorParametrization):
intro = Text("## Grasshopper app \n This app parametrically generates and visualises a 3D model of a box using a Grasshopper script. \n\n Please fill in the following parameters:")

# Input fields
width = NumberField('Width', default=5)
length = NumberField('Length', default=6)
height = NumberField('Height', default=7)


class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization
  1. Refresh your app, and you should see the input fields there.

Add the Python code to run Grasshopper

Now the app code can be extended to integrate the Grasshopper script. Change the code in app.py to the code below:

from io import BytesIO
import json

from viktor import ViktorController
from viktor.parametrization import ViktorParametrization
from viktor.parametrization import NumberField
from viktor.parametrization import Text
from viktor.external.generic import GenericAnalysis
from viktor.views import GeometryView
from viktor.views import GeometryResult


class Parametrization(ViktorParametrization):
intro = Text("## Grasshopper app \n This app parametrically generates and visualizes a 3D model of a box using a Grasshopper script. \n\n Please fill in the following parameters:")

# Input fields
width = NumberField('Width', default=5)
length = NumberField('Length', default=6)
height = NumberField('Height', default=7)


class Controller(ViktorController):
label = 'My Entity Type'
parametrization = Parametrization

@GeometryView("Geometry", duration_guess=10, update_label='Run Grasshopper')
def run_grasshopper(self, params, **kwargs):

# Create a JSON file from the input parameters
input_json = json.dumps(params)

# Generate the input files
files = [('input.json', BytesIO(bytes(input_json, 'utf8')))]

# Run the Grasshopper analysis and obtain the output files
generic_analysis = GenericAnalysis(files=files, executable_key="run_grasshopper", output_filenames=["geometry.3dm"])
generic_analysis.execute(timeout=60)
threedm_file = generic_analysis.get_output_file("geometry.3dm", as_file=True)

return GeometryResult(geometry=threedm_file, geometry_type="3dm")

SDK version

This code requires support for 3dm files, which is available since SDK v14.4.0. Make sure use this SDK version or higher in your requirements.txt file.

If you now refresh your app, you should see the following:

After pressing the Run Grasshopper button (be sure that the worker, Rhino and Grasshopper are running), you should see that Rhino Compute is run by the worker which will result in the following:

Congratulations, you now have a made a VIKTOR app with a Grasshopper model running behind it!

4. Use your own Grasshopper model

If you would like to integrate your own Grasshopper model in VIKTOR, you can adapt the app you just created. Take the following steps:

Extend your Grasshopper model

As explained in this section, some specific things need to be defined in the Grasshopper model to make the integration work.

  1. Connect your specific input parameters by Hops components. In order to update the parameters via Rhino Compute, create Hops Get Components for the parameters you want to update.

  2. Add the Context Bake component. The Grasshopper node Context Bake is needed to bake the model.

After implementing these changes, check if the Python script still runs successfully (run run_grasshopper.py). Be aware that in the Python file, the name of the Grasshopper file is defined: change this name to match with your file name.

Adjust the VIKTOR app code

In the VIKTOR app code adjust the parametrization to match with your required input parameters.

The rest of the code should not require any changes to work.

To infinity and beyond

Great work! You are now able to create an app that can integrate with an external installation of Grasshopper through a Generic Worker!

Of course, the journey doesn't end here. Check out some of our other tutorials or go to the next section where you can see the different paths you can follow in your journey to learn more about VIKTOR.