Grasshopper API - instantiation of Grasshopper.Instances

Hi all,

I’m building a Rhino plugin and I’d like some geometry stored in the plugin to auto-populate a point collection in Grasshopper, and then open the Grasshopper editor on-screen.

However, I run into "Object reference not set to an instance of an object errors’ on both the ActiveCanvas, and (if I comment the former) the DocumentEditor.

How can I ensure these have been instantiated?

I have read the docs to no avail. Forgive me for being a novice.

using System;
using Rhino;
using Rhino.Commands;
using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
using System.IO;
using Ninject;
using PileDriver.Models.Interfaces;
using Grasshopper.Kernel.Parameters;

namespace PileDriver.Commands
{
    public class IntoGH : Command
    {
        private readonly ISupportSystem _supportSystem;

        public IntoGH()
        {
            Instance = this;
            // Get ISupportSystem instance from Ninject kernel
            IKernel kernel = PileDriverPlugin.Instance.GetKernel();
            _supportSystem = kernel.Get<ISupportSystem>();
        }

        public static IntoGH Instance { get; private set; }

        public override string EnglishName => "IntoGH";

        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            try
            {
                if (_supportSystem.FoundationTracePoints == null || !_supportSystem.FoundationPolylineIsClosed())
                {
                    RhinoApp.WriteLine("Please create a closed foundation trace first.");
                    return Result.Failure;
                }

                string scriptPath = Path.Combine(
                    Path.GetDirectoryName(typeof(IntoGH).Assembly.Location),
                    "Scripts",
                    "AutoPiler.gh"
                );

                if (!File.Exists(scriptPath))
                {
                    RhinoApp.WriteLine($"Cannot find Grasshopper script at: {scriptPath}");
                    return Result.Failure;
                }

                var io = new Grasshopper.Kernel.GH_DocumentIO();
                if (!io.Open(scriptPath))
                {
                    RhinoApp.WriteLine("Failed to load Grasshopper file.");
                    return Result.Failure;
                }

                var ghDoc = io.Document;
                if (ghDoc == null)
                {
                    RhinoApp.WriteLine("No document found in the Grasshopper file.");
                    return Result.Failure;
                }


                // Find parameters
                IGH_Param foundationParam = FindParameter(ghDoc, "Foundation");
                IGH_Param loadBearersParam = FindParameter(ghDoc, "Load-Bearers");
                IGH_Param tieBeamsParam = FindParameter(ghDoc, "Tie Beams");
                IGH_Param pilesParam = FindParameter(ghDoc, "Existing Piles");

                if (foundationParam == null || loadBearersParam == null ||
                    tieBeamsParam == null || pilesParam == null)
                {
                    RhinoApp.WriteLine("Could not find all required input parameters in the Grasshopper script.");
                    return Result.Failure;
                }

                // Populate foundation polyline
                var foundationData = new GH_Structure<GH_Point>();
                foreach (var point in _supportSystem.FoundationTracePoints)
                {
                    foundationData.Append(new GH_Point(point), new GH_Path(0));
                }
                ((Param_Curve)foundationParam).SetPersistentData(foundationData);

               

                // Add the document to Grasshopper's document server
                Instances.DocumentServer.AddDocument(ghDoc);

                // Enable solution
                ghDoc.Enabled = true;
                ghDoc.ExpireSolution();

                

                // Set the loaded document as active AAAAAAAAAAAAAAAAAAAAAAAAAAAA
                Instances.ActiveCanvas.Document = ghDoc;

                // Show Grasshopper window
                Instances.DocumentEditor.Show();

                // Confirm successful load to user
                RhinoApp.WriteLine("Successfully loaded and populated Grasshopper script.");

                // Return success
                return Result.Success;
            }
            catch (Exception ex)
            {
                RhinoApp.WriteLine($"Error: {ex.Message}");
                return Result.Failure;
            }
        }

        private static IGH_Param FindParameter(GH_Document ghDoc, string nickname)
        {
            foreach (var obj in ghDoc.Objects)
            {
                if (obj is IGH_Param param && param.NickName.Equals(nickname, StringComparison.OrdinalIgnoreCase))
                {
                    return param;
                }
            }
            return null;
        }
    }
}```

You have to initialize GH before being able to access the canvas.

Before openning GH, you should subscribe to this event

then you can open GH via Instances.DocumentEditor.Show() and on the event handler function you can access the ActiveCanvas instance. However I’m not sure I can’t remember if Instances.ActiveCanvas.Document = ghDoc; is the right way to open a document.

To avoid UX issues (your users may have openned GH before using your command), it’s convenient to subscribe to this event from the plugin class or a controller static class that it’s initialized when your plugin loads.

1 Like

Thank you so much!

If anyone is interested, or wishes to improve on it, my code ended up looking like this

namespace PileDriver.Commands
{
    public class IntoGH : Command
    {
        private readonly ISupportSystem _supportSystem;
        
        private string _scriptPath;

        public IntoGH()
        {
            Instance = this;
            // Get ISupportSystem instance from Ninject kernel
            IKernel kernel = PileDriverPlugin.Instance.GetKernel();
            _supportSystem = kernel.Get<ISupportSystem>();

            _scriptPath = Path.Combine(
                    Path.GetDirectoryName(typeof(IntoGH).Assembly.Location),
                    "Scripts",
                    "AutoPiler.gh");

            // Subscribe to GH creation
            Instances.CanvasCreated += OnCanvasCreated;
        }

        public static IntoGH Instance { get; private set; }

        public override string EnglishName => "IntoGH";

        protected override Result RunCommand(RhinoDoc doc, RunMode mode)
        {
            try
            {
                if (_supportSystem.FoundationTracePoints == null || !_supportSystem.FoundationPolylineIsClosed())
                {
                    RhinoApp.WriteLine("Please create a closed foundation trace first.");
                    return Result.Failure;
                }


                if (!File.Exists(_scriptPath))
                {
                    RhinoApp.WriteLine($"Cannot find Grasshopper script at: {_scriptPath}");
                    return Result.Failure;
                }

                var io = new GH_DocumentIO();
                if (!io.Open(_scriptPath))
                {
                    RhinoApp.WriteLine("Failed to load Grasshopper file.");
                    return Result.Failure;
                }

                var ghDoc = io.Document;
                if (ghDoc == null)
                {
                    RhinoApp.WriteLine("No document found in the Grasshopper file.");
                    return Result.Failure;
                }


                // Find parameters
                IGH_Param foundationParam = FindParameter(ghDoc, "Foundation");

                if (foundationParam == null || loadBearersParam == null ||
                    tieBeamsParam == null || pilesParam == null)
                {
                    RhinoApp.WriteLine("Could not find all required input parameters in the Grasshopper script.");
                    return Result.Failure;
                }

                // Populate foundation polyline
                var foundationData = new GH_Structure<GH_Point>();
                foreach (var point in _supportSystem.FoundationTracePoints)
                {
                    foundationData.Append(new GH_Point(point), new GH_Path(0));
                }
                ((Param_Point)foundationParam).SetPersistentData(foundationData);

                // Add the document to Grasshopper's document server
                Instances.DocumentServer.AddDocument(ghDoc);

                // Enable solution
                ghDoc.Enabled = true;
                ghDoc.ExpireSolution();

                // Confirm successful load to user
                RhinoApp.WriteLine("Successfully loaded and populated Grasshopper script.");

                // Return success
                return Result.Success;
            }
            catch (Exception ex)
            {
                RhinoApp.WriteLine($"Error: {ex.Message}");
                return Result.Failure;
            }
        }

        private static IGH_Param FindParameter(GH_Document ghDoc, string nickname)
        {
            foreach (var obj in ghDoc.Objects)
            {
                if (obj is IGH_Param param && param.NickName.Equals(nickname, StringComparison.OrdinalIgnoreCase))
                {
                    return param;
                }
            }
            return null;
        }

        private void OnCanvasCreated(GH_Canvas canvas)
        {

            Instances.ActiveCanvas.Document = Instances.DocumentServer[Instances.DocumentServer.IndexOf(_scriptPath)];

        }
    }
}