Grasshopper

algorithmic modeling for Rhino

Hi all,

I need to save some data (string) into the grasshopper file so that is visible to all components. 

With the snipped below I save custom data for each individual component. How would I go about saving the "someStringToSave" so that it is written only once into the archive and visible to all component on the canvas.

Thanks a bunch in advance.

T

public override bool Write(GH_IO.Serialization.GH_IWriter writer)
{
writer.SetString("settings", someStringToSave );
return base.Write(writer);
}

public override bool Read(GH_IO.Serialization.GH_IReader reader)
{
string savedString= reader.GetString("settings");

}

Views: 2967

Replies to This Discussion

I don't get it, data in the gh file and components on the canvas are never really in the same 'space'. Does each component instance have a copy of these settings that you are keeping synchronised somehow? Are the settings stored in a global place which is not deserializable?

Hi David - thanks for the quick reply.

I have some data that all components need to access. I currently store this in one separate text file (this takes care of the synchronization - since it is rewritten every time a change is made). However, the separate file is quite a hassle I would like to store it inside the Grasshopper archive. If believe I would need to store it in a separate "chunk" or closer to the root level so all component can read and write one "global" chunk in the Grasshopper archive.

Is that possible?

The above code would store multiple copies of the same data within each component chunk. I could figure out a way to synchronize these duplicates if this is the best way to do it.

Best,

T

It's something that should be part of the (de)serialization SDK, but it isn't. 

The biggest problem here is not so much the writing/reading part (it's ok if you store the same data in every component, GH files are zip compressed so it won't bloat the file), but the accessing at runtime part. Using a file on the disc or a static field means that your data isn't just shared amongst all components in the same file, but amongst all components in all files currently loaded by a specific instance of Rhino+Grasshopper. This may not be what you want, if you're looking to provide per-document data.

I've got some more questions:

  • Where does this shared data come from?
  • If a component with different shared data is copy-pasted into another document, what happens to the shared data on that component?

Hi David,

it is a "MaterialLibrary" that sits right next to the gha plugin file. The data is shared between all open files. This was intended but proved to be confusing for users - especially when files are shared across multiple computers (one would have to copy the external text file too).

Hence, I would like to change the behavior to "per document data" and provide an export function.

Would you recommend storing this data in the component chunk even if it is duplicated multiple times? This way one would be able to copy and paste the data with a component from one archive to another.

I'd have one or more components per file that maintain the libraries, and all other components rely on those instances. It doesn't have to be hooked up to anything, it just needs to exist and expose a bunch of public methods/properties other components can hook into.

Benefits are that it'll be easy to swap between material libraries, or load two or more at the same time.

Another benefit is that the (de)serialization and sharing of libraries becomes really straightforward.

Drawback is that you have to deal with conflicting material definitions. This is not a huge problem, you can test for this whenever a solution starts, or when a material library object is changed/added/removed.

Another drawback is that it circumvents the typical Grasshopper logic, in that you'll have some objects that provide data even though there are no wires that visually share the data (unless of course you add a 'material library' type in which case the libraries can be passed around through regular channels, but it might mean a lot of extra wires). There are however already plugins that break the standard operating procedure for Grasshopper and people do not seem to have a huge amount of trouble adapting to that.

Could you explain a bit more how such a setup would have to look like?

If I create a static object outside of the GH component template to pass data between components without wires, the data is also passed between all open documents. Or am I missing something?

It wouldn't be a static object in your code, it would be an IGH_DocumentObject type class on the canvas. The components which rely on these library objects will have to look in the GH_Document to find all 'loaded' libraries within the current document.

If this is a solution you think might work, I'll be happy to put an example together.

It might look (vaguely) like this.

And it actually looks like this.

Hi David - thanks a ton for your help. The example above looks great!!!! Would you be able to share the code for that?

I was able to get it to work with a helper function that scans the doc for components that have a library attached. I then try to sync it by copying the same pointer around. Any thoughts? The function looks like this:


public class LibrarySync
{
public static Guid component1 = new Guid("4DB7F740-24CB-49C2-BF06-3F6003A38C38");
public static Guid component2 = new Guid("17656BD9-0716-48AA-9D2F-F202157D7C89");

public static Lib getDocLibraryPointer(Guid thisInstanceGuid)
{
HashSet<Lib> Libraries = new HashSet<Lib>();
Lib Library = loadDefualtLibrary();
GH_Document doc = Grasshopper.Instances.ActiveCanvas.Document;
foreach (IGH_DocumentObject docObject in doc.Objects) //for every GH component in document
{
if (docObject.ComponentGuid != component1 && docObject.ComponentGuid != component2)continue;
if (docObject.InstanceGuid == thisInstanceGuid) continue;
if (component1 == docObject.ComponentGuid)
{
GHComp1 obj = docObject as GHComp1;
if (obj != null)
{
if (!Libraries.Contains(obj.Library)) Libraries.Add(obj.Library);
}
}
else if (component2 == docObject.ComponentGuid)
{
GHComp2 obj = docObject as GHComp2;
if (obj != null)
{
if (!Libraries.Contains(obj.Library)) Libraries.Add(obj.Library);
}
}
if (Libraries.Count > 0) return Libraries.ElementAt(0);
else return null;
}
}
}

If you think this solution will work I'll add the last few methods needed to make it a nicely rounded API. It has a lot of empty boilerplate code but you'll just have to fill that in yourself.

I'll upload the code once it's operational.

Ok so 2000 lines of code with 5 class definitions:

  • An immutable Material class.
  • A mutable Material Library class.
  • An object which provides a Material Library on the GH canvas.
  • Attributes for the above object.
  • An example component which uses the material library.
Attachments:

RSS

About

Translate

Search

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service