algorithmic modeling for Rhino
Basically what I am trying to accomplish is to create a component that reads an external settings text file, creates a dictionary from it and makes that Settings dictionary with its values accessible to other classes in the add-on. I'm getting stuck because everything seems to be enclosed in the SolveInstance function and I'm not entirely sure what can be changed without creating a problem for the input/ output functions of the component.
Currently I have:
protected override void SolveInstance(IGH_DataAccess DA)
{
List<string> inputList = new List<string>();
if (!DA.GetDataList(0, inputList)) return;
inputList.ToArray();
char splitChar = '=';
Dictionary<string, string> Settings = new Dictionary<string, string>();
for (int i = 0; i<inputList.Length; i++)
{
string[] parts = inputList[i].Split(splitChar);
string dkey = parts[0];
string dvalue = parts[1];
Settings.Add(dkey,dvalue);
}
DA.SetData(0, Settings);
}
What is the best way to make the data collected in the SolveInstance function in the template GH Addon Class accessible another class? Can you change it from being protected override to a public something without causing problems?
Tags:
Hi Adam,
what sort of "other classes"?
You cannot change the access modifier on a method you override, SolveInstance is and forever will be a protected method. What you can do is store your Dictionary in a place that other classes have access to. But first I need to know what classes want access to the dictionary and when.
--
David Rutten
david@mcneel.com
Poprad, Slovakia
Hi David,
Thanks for replying so quickly.
The classes would be in other components that are a part of the plugin namespace. So when the Settings component creates a Dictionary from a text file, the other components would immediately be able to use the Dictionary as a part of their own SolveInstance method.
I initially tried outputting the dictionary itself from the Settings component, but then realized I would have to create a dictionary data type for it to be used by other components. So I wondered if it would perhaps be easier to make the the Dictionary accessible to the SolveInstace method of the other components without using wires:
protected override void SolveInstance(IGH_DataAccess DA)
{
Dictionary <string,string> Settings = new Dictionary<string,string>();
if (!DA.GetData(0, ref Settings)) return;
double nD = double.Parse(Settings["n_d"]);
double fD = double.Parse(Settings["f_d"]);
double FlM = ((Math.Pow(nD / 2, 2) * Math.PI)/(Math.Pow(fD / 2, 2) * Math.PI));
DA.SetData(0, FlM);
}
What if the SolveInstance methods of other components is called before you update the dictionary?
You can in fact pass any kind of data between components, you just need to wrap it up in a GH_ObjectWrapper type and use Generic parameters.
--
David Rutten
david@mcneel.com
Poprad, Slovakia
I would need to provide an error catching statement so that if the other components are used before you have settings for them then they would throw up an error telling you to locate a settings file with the Settings component. The idea is that they need some base settings in order to function, but the base settings can be changed outside grasshopper depending on which settings profile the user wants to use.
That's a bit counter-grasshopper. If you open a document with a Settings Reader component and a Settings User component, then it might fail to work right away. But it will work the second time around. Or it might just work right away. This is inconsistent behaviour that will confuse people.
Another problem is that you may have more than one Setting Reader components. Which settings ought to be used? Passing settings around through wires fixes both these problems. See the attached file for an example of how to pass non-grasshopper types between components using the GH_ObjectWrapper.
--
David Rutten
david@mcneel.com
Poprad, Slovakia
I see your point. Though it may also annoy people to have to connect every Settings User component to the Settings Reader component to make their definitions work. Maybe I need to rethink how the Settings work with the components a little bit.
Thanks a lot for the example! Made with version 0.9.0002 I see ;)
If you only want a single settings instance to exist, then I think you need to make it a non-component interface. Basically, somewhere in your assembly you have a Shared settings dictionary. Whenever this dictionary is accessed and it doesn't yet exist, you popup a FileOpenWindow and demand that the user selects a settings file.
This way; no extra wires, no multiple settings collisions, no solve-order problems.
If you really want to do it inside a single Grasshopper file, then you can create a Settings object (not a component), which knows when to read a settings file, and can do so outside of a solution. But then you still have the problem that people can create two or more of these competing settings.
--
David Rutten
david@mcneel.com
Poprad, Slovakia
That's a good idea! Looks like I may have to research some more into how to do that though.
A side note, I can't get the ObjectWrapper to work in c#. I translate your code to:
Dictionary<string, string> dict = new Dictionary<string, string>();
//create dictionary from input
Grasshopper.Kernel.Types.GH_ObjectWrapper wrapper = new GH_ObjectWrapper(Settings);
DA.SetData(0, wrapper);
and then in the Settings User component it takes it in by:
Dictionary <string,string> Settings = new Dictionary<string,string>();
if (!DA.GetData(0, ref Settings)) return;
if ((Settings == null))
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Settings Dictionary must be a valid dictionary");
return;
}
but when I compile and try to plug them into each other in grasshopper the Settings User component still tries to convert a string to a dictionary. Did I translate from VB to C# incorrectly?
Thanks,
Adam
Grasshopper.Kernel.Types.GH_ObjectWrapper wrapper = new GH_ObjectWrapper(Settings);
should be
Grasshopper.Kernel.Types.GH_ObjectWrapper wrapper = new GH_ObjectWrapper(dict);
--
David Rutten
david@mcneel.com
Poprad, Slovakia
Oh sorry, I did. I just changed the code for pasting here so it wasn't confusing, but forgot to change all the instances of dict to Settings.
Yeah, in my code it is:
Dictionary<string, string> dict = new Dictionary<string, string>();
//create dictionary from input
Grasshopper.Kernel.Types.GH_ObjectWrapper wrapper = new GH_ObjectWrapper(dict);
DA.SetData(0, wrapper);
but still doesn't work.
What does the output parameter tooltip claim?
--
David Rutten
david@mcneel.com
Poprad, Slovakia
When I hover over the output of the Read Settings component it says
System.Collections.Generic.Dictionary`2[System.String,System.String]
but the other end says it "Invalid Cast: String > Dictionary'2"
Welcome to
Grasshopper
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
Added by Parametric House 0 Comments 0 Likes
© 2024 Created by Scott Davidson. Powered by