【Grasshopper进阶】Grasshopper外部调用

本文介绍如何利用.NET Framework下的Remoting技术实现外部程序控制Grasshopper画布组件进行数据操作,包括重新计算等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主旨是介绍“进程间通讯”在Grasshopper中的应用。

常用场景:手头已经有一个程序,这个程序想控制Grasshopper画布中某些组件进行一些数据操作,这个程序是独立Rhino和Grasshopper之外运行的。

另一个程序来控制 Grasshopper 中的组件。


进程之间通讯

Windows平台下,进程间通讯称为“Interprocess Communications”,具体详见msdn文档,有多重实现模式,在此就不赘述了:

https://docs.microsoft.com/en-us/windows/win32/ipc/interprocess-communications
(中文版暂未提供)

鉴于Rhino/Grasshopper是.NET Framework平台,本文选择一个最简单的实现方法来实现这一点 —— Remoting。

关于Remoting的介绍:

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.remoting?view=netframework-4.8

实现方法

Grasshopper电池中新开一个 自定义线程 用来接收外部程序的调用,外部程序与Grasshopper中新建的 自定义线程 通过Remoting协议实现通讯,这个线程负责依照外部程序指令对Grasshopper进行相应操作。

本文的例子是通过外部程序使得Grasshopper中重新计算(Recompute)。

WeChat Screenshot_20210305163758


  1. 新建一个 .Net Framework Library项目,里面用来定义进程通讯的对象的接口。

namespace IPCLibrary
{
    public interface IPCInterface
    {
        // 定义一个能够被外部调用的接口,具体实现在Grasshopper中完成
        void Recompute(); 
    }
}

将该项目编译,构建一个 IPCInterface.dll 文件,该文件在接下来会被引用。


  1. 新建一个Grasshopper电池项目,并引用步骤1中生成的 IPCInterface.dll 文件。这个项目主要是实现两个部分的内容:
    (1)依据步骤1中定义的接口,实现一个对象用来对Grasshopper实现所需的操作;
    (2)在SolveInstance内部开启新线程,用于实例化 步骤(1) 中的对象的静态属性以及注册通讯协议至操作系统。

using Grasshopper.Kernel;
using IPCLibrary;
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Threading;

namespace SolutionExpirer
{
    internal class SolutionExpirer : MarshalByRefObject, IPCInterface
    {
        internal static GH_Component component; // 静态属性,在线程启动时指定为线程发起者
        public void Recompute() => component.OnPingDocument().NewSolution(true); // 实现Grasshopper重算逻辑
    }
    public class SolutionExpirerComponent : GH_Component
    {
        public SolutionExpirerComponent()
          : base("SolutionExpirer", "SEer",
              "",
              "IPC", "IPC")
        { }
        protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager) { }
        protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager) { }

        Thread thd;         // 定义线程
        int slvCount = 0;   // 用于存储该电池总共的运行次数(证明真的ExpireSolution了)
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            slvCount++;
            Message = slvCount.ToString();   // 用来显示SolveInstance自该电池在画布上起,总共运行了几次
            if (thd != null) return;
            thd = new Thread(() =>
            {
                var channel = new IpcServerChannel("GHMFIPCD");
                ChannelServices.RegisterChannel(channel, false);
                RemotingConfiguration.RegisterWellKnownServiceType(typeof(SolutionExpirer), "SE", WellKnownObjectMode.SingleCall);
                SolutionExpirer.component = this; // 指定静态属性
                while (true) { } // 线程保活
            });
            thd.Start(); // 开启线程
        }
        protected override System.Drawing.Bitmap Icon => null;
        public override Guid ComponentGuid => new Guid("*** *** Apply a new Guid here *** ***"); 
    }
}

  1. 外部程序调用:这里采用一个Console程序来实现 —— 新建一个Visual Studio命令行项目,将步骤1中的 IPCInterface.dll 加入引用。

using IPCLibrary;
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;

namespace ClientSide
{
    class Program
    {
        static void Main(string[] args)
        {
            var channel = new IpcClientChannel();
            ChannelServices.RegisterChannel(channel, false);

            var url = @"ipc://GHMFIPCD/SE";  // 分别对应Grasshopper电池定义中的Channel名字及ServiceType名字
            var remoteObj = (IPCInterface)Activator.GetObject(typeof(IPCInterface), url);

            remoteObj.Recompute();
        }
    }
}

本质上来说,是使用Activator.GetObject()来实例化了一个在Grasshopper内的对象(远程对象),而在命令行程序中可以作为本地对象来使用。

将上述命令行程序运行的结果就是Recompute()方法被执行,Grasshopper中画布上的所有电池将会被Expire并重启运算。运行结果:

Record_2021_03_05_18_03_00_155

图中,靠上部的电池是一个随机数生成器,每次会随即生成一个0~1之间的浮点数。可以看到,每次Recompute的时候,都会生成一批新的浮点数。

左侧命令行运行的是步骤3中的生成的外部程序。可以看到,每次程序运行时都成功地将使Grasshopper重新计算了。电池本身的计数器也在不断增长。

生成器,每次会随即生成一个0~1之间的浮点数。可以看到,每次Recompute的时候,都会生成一批新的浮点数。

左侧命令行运行的是步骤3中的生成的外部程序。可以看到,每次程序运行时都成功地将使Grasshopper重新计算了。电池本身的计数器也在不断增长。

此时如果我们对命令行程序(步骤3中的代码)进行重构、任何更改,都不会影响到Rhino或者Grasshopper的运行。甚至可以在Rhino运行的时候进行代码调试。在某些特定情况下,还是十分有效的。

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值