Hacking the Grasshopper Hops Component

Hops is meant to let you re-use of Grasshopper script parts across multiple documents, and consume Rhino Compute services that are hosted online or on a local network. It provides a single component, that when given a path to a local file or network endpoint, turns itself into a component representing the function and handles communication with the source. That is, it shows a new icon, sets up the appropriate inputs and outputs, makes requests and returns responses either to a local file or remote service.

Besides making calls to other local Grasshopper documents, and remote Rhino Compute servers, Hops also works with any Flask-based Python1 server that uses the rhino3dm python library, through a REST API. An example is included in the Rhino Compute repository. This is great because it provides a way to use "real" Python, independent of the Rhino application, incorporating third-party libraries like NumPy, using your preferred editor etc2.

But what else can it be used for? One potential opportunity here is you could hypothetically build a single API accessible from either Grasshopper or a web app. Even though this use case isn't documented, you don't actually need Rhino Compute or rhino3dm on the server to use Hops. Given that the Hops code is open-source, you could go as far as adapting the code to use a properly open format like well-known binary rather than openNURBS for the geometry representation, making it easier to work with geospatial libraries like shapely, but let's leave that for another time.

Using the Hops Grasshopper component as-is, can we adapt the server example to work without using any Rhino-specific code? Here's what I did:

  • using a two-machine setup…
    • a laptop running NixOS, to develop and run the server
    • a windows desktop running Windows, Rhino and Grasshopper
    • on the development machine:
    • set up shell.nix and .envrc for the developent environment
    • the python environment just needs flask for now
    • port 5000 should be open so the Flask service is reachable over network
  • in examples/app.py
    • comment out rhino3dm import
    • also comment out endpoints that use rhino3dm calls (for now), srf4pt and pointat
    • finally add the arguments host='0.0.0.0', port=5000 to the app.run() call
  • now in ghhops_server/__init__.py
    • comment out all calls to params._init_...
    • that is for both rhino3dm and rhinoinside init functions
  • finally in ghhops_server/params.py
    • RHINO_TOJSON = lambda v: json.dumps(v, cls=_HopsEncoder)
    • CONVERT_VALUE = lambda v: return v
    • on line 210, (for param_value_item in input_data["InnerTree"]["0"]:)
    • change the outer key from "0" to "{0}"
  • you should be able to start and test the development server:
    • run python app.py from examples
  • now test it on the windows machine:
    • in an empty grasshopper document, set up a new hops component as shown below
    • (right click to get Path and Enabled inputs to appear)
    • A, B inputs and S output will appear if Hops is able to reach the server
    • S should have the result of the operation of A and B
98021aba30938ddf.png

Footnotes:

1

Specifically, CPython (not the IronPython provided by Rhino/Grasshopper)

2

Rhino 8 offers new Python 3 features and an improved editor, I haven't looked closely at the implications of this yet.