I would like to load and save a configuration from and to a file in Grasshopper using python, which works, apart from the right save function trigger.
Once loaded, the configuration is saved in a dict in the sc.sticky. The config file should automatically (without for example pressing a button) reflect changes made to the configuration, but I don’t know how to properly trigger the save function.
Right now, I am using a Timer-component to periodically trigger a save config python component.
I checked if there is an event that I could use for this (https://developer.rhino3d.com/wip/api/grasshopper/html/N_Grasshopper_Kernel.htm), but I didn’t find a suitable one. Additionally, it doesn’t seem like one can even use these events from Python, only from VB and C#. Is it possible in GH to call python from a VB or C# script?
Another solution would be calling some python component from another python component. I did not find anything on this here either.
Of course, I could trigger the update directly by connecting all of the components, but I’d rather not do this.
Hello Mahdiyar, thanks for your answer!
How fragile is this solution? When copying these elements from one file to another, the ids change, if you copy them as a cluster they ids stay the same. Is this generally true?
I think a version which is using named groups (that’s the way Rhino computed identified elements too as I learned today) would be more robust.
Unfortunately I haven’t found a way to find out which Grasshopper groups a component is part of yet.
I checked the forum for solutions (Is there a way to accesss groups-information in an object? this one is talking about Rhino groups, not about GH groups), but coudn’t find anything on it.
#ID
from scriptcontext import sticky
comp = ghenv.Component.OnPingDocument().FindObject(id, False)
sticky['i'] = v
comp.ExpireSolution(True)
#Name
from scriptcontext import sticky
sticky['i'] = v
for obj in ghenv.Component.OnPingDocument().Objects:
if obj.NickName in names:
obj.ExpireSolution(True)
#Group
from scriptcontext import sticky
import Grasshopper as gh
def FindPythonObjectInCurrentGroup():
pythonObjects = []
ghObjects = ghenv.Component.OnPingDocument().Objects
for obj in ghObjects:
if type(obj) is gh.Kernel.Special.GH_Group:
if obj.ObjectIDs.Contains(ghenv.Component.InstanceGuid):
group = obj
for obj in ghObjects:
if ghenv.Component.ComponentGuid == obj.ComponentGuid:
if ghenv.Component.InstanceGuid != obj.InstanceGuid:
if group.ObjectIDs.Contains(obj.InstanceGuid):
pythonObjects.append(obj)
return pythonObjects
sticky['i'] = v
pythonObjects = FindPythonObjectInCurrentGroup()
for obj in pythonObjects:
obj.ExpireSolution(True)
Hello! I know that this is a python post, but I was trying to create something similar in C# with a sender component to a clustered receiver, can anyone help me plaese?
Sender:
using System;
using Grasshopper.Kernel;
public class SenderComponent : GH_Component
{
public SenderComponent() : base("Sender", "S", "Send numeric data to receiver", "Test", "Data") { }
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddNumberParameter("Data", "D", "Numeric data to send", GH_ParamAccess.item);
}
protected override void RegisterOutputParams(GH_OutputParamManager pManager) { }
protected override void SolveInstance(IGH_DataAccess DA)
{
double data = 0;
if (!DA.GetData(0, ref data)) return;
// Get the nickname of the target receiver
string targetNickname = "ReceiverNickname";
// Find the remote component with the given nickname within the cluster
GH_Component targetComponent = null;
foreach (IGH_DocumentObject obj in OnPingDocument().Objects)
{
if (obj is GH_Cluster)
{
GH_Cluster cluster = obj as GH_Cluster;
foreach (IGH_Component clusterComponent in cluster.ClusterObjects(true))
{
if (clusterComponent.NickName == targetNickname && clusterComponent is GH_Component)
{
targetComponent = clusterComponent as GH_Component;
break;
}
}
}
}
// Check if the target component was found
if (targetComponent != null)
{
// Send data to the target component
targetComponent.Params.Input[0].AddVolatileData(new GH_Path(0), 0, data);
}
// Expire solution to update the changes
ExpireSolution(true);
}
public override Guid ComponentGuid
{
get { return new Guid("GUID_HERE"); }
}
}
Sender:
using System;
using Grasshopper.Kernel;
public class ReceiverComponent : GH_Component
{
public ReceiverComponent() : base("Receiver", "R", "Receive numeric data from sender", "Test", "Data") { }
protected override void RegisterInputParams(GH_InputParamManager pManager) { }
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddNumberParameter("Data", "D", "Received numeric data", GH_ParamAccess.item);
}
protected override void SolveInstance(IGH_DataAccess DA)
{
double data = 0;
// Receive data from the sender component
DA.GetData(0, ref data);
// Do something with the received data...
// Output the received data
DA.SetData(0, data);
}
public override bool Read(GH_IReader reader)
{
// Perform any additional reading here if needed
return base.Read(reader);
}
public override bool Write(GH_IWriter writer)
{
// Perform any additional writing here if needed
return base.Write(writer);
}
protected override void ExpireDownStreamObjects()
{
// Expire downstream objects to trigger a re-computation when data is received
OnPingDocument().NewSolution(true);
base.ExpireDownStreamObjects();
}
public override Guid ComponentGuid
{
get { return new Guid("GUID_HERE"); }
}
}