Grasshopper

algorithmic modeling for Rhino

The attached file shows how to inject custom data into an existing *.gh or *.ghx file.

(This is a response to a private tech support request)

Views: 2514

Attachments:

Replies to This Discussion

Thanks David, it's very interesting.

It's possible to find/recuperate this data in grasshopper?

Not without another C#/VB/Python component. But yes, the GH_IO.dll can be used to load files and extract specific values from it without first loading that file in Grasshopper. In fact when Grasshopper loads a file with custom data, it will ignore that custom data because it does not know it should be looking for it.

Ok david it's possible to share this C# component.

Is it possible to integrate any type of data ?

Best,

I didn't write that yet, but I can.

GH_IO supports a range of standard types, but since it also allows you to store strings and byte-arrays, you can store any type of data you want.

Mirror image code. It would have been better to also store a count integer telling us how many breps have been stored, but we can also just keep trying to read more and more breps until we reach the last one.

Attachments:

Thanks david, with brep it's ok for me.

For another object, what classes should I use instead of "Grasshopper.Kernel.GH_Convert.CommonObjectToByteArray" for example string or numer ?

It would be interesting to injecting number or text into a gh file.

Thanks.

The GH_IWriter and GH_IReader types that are used to access the GH file chunks support several common types. All data in *.gh files is stored both by key (string) and index (int). The two together need to be unique. This makes it easier to store collections of items that use the same key. If you don't specify an index, -1 is assumed.

Another key point about the GH_IO database format is that it's made up of 'chunks'. Chunks are accessed by GH_IWriter objects when adding data to them and GH_IReader objects when harvesting data from them. Technically, GH_Chunk implements both the writer and the reader interfaces so you could cast them on the spot, but I recommend against that.

A chunk may contain any number of sub-chunks (each with a unique key+index pair) and any number of items (each with a unique key+index pair). Items are stored as type-safe data, and you can get at items directly and examine their types, however it is overwhelmingly likely that you know what type they are because you were also responsible for creating them.

You can example gh and ghx files by dragging them onto the canvas, then selecting the Examine File option by pressing the E key or dropping the file onto the magnifier glass icon.

It doesn't matter what method you use to create byte arrays. The CommonObjectToByteArray method is just an easy-to-use wrapper around data types that come from OpenNurbs. If you want to store an array of Point3d types, you can convert that to a byte array as well, but you'll need to do so yourself, there's nothing in Grasshopper that does it for you.

Wow I had never noticed this possibility. The great david!

File option it's very important...

For the C# script for written data, I have not managed to change it to values or texts.

GH_Archive archive = new GH_Archive();
if (!archive.ReadFromFile(source))
throw new Exception("File could not be read");

GH_Chunk root = archive.GetRootNode;
if (root == null)
throw new Exception("File has no root");

GH_IWriter writer = root.CreateChunk(Key);

int index = -1;
foreach (String text in Text)
{
index++;
byte[] stringData = Grasshopper.Kernel.GH_Convert.CommonObjectToByteArray(text);
writer.SetByteArray("text", index, stringData);
}

//System.IO.File.WriteAllBytes(target, archive.Serialize_Binary());
archive.WriteToFile(target, true, false);

1. Error (CS1502): La méthode surchargée correspondant le mieux à 'Grasshopper.Kernel.GH_Convert.CommonObjectToByteArray(Rhino.Runtime.CommonObject)' possède des arguments non valides (line 84)

2. Error (CS1503): Argument 1 : impossible de convertir de 'string' en 'Rhino.Runtime.CommonObject' (line 84)

It would be interesting to injecting number or text into a gh file.

With C# code, of course !

Antother question:

It's possible to write multiple Keys ?

Thanks for all.

Well, you'd only use the CommonObjectToByteArray method to convert something like a Mesh or a Brep or a Curve into the OpenNurbs byte data. You don't have to convert strings to byte-arrays, as you can store strings directly with writer.SetString(). Or you can store numbers directly with writer.SetDouble() etc. etc.

You can add any number of keys you want, and you can add any number of subchunks to the one made by root.CreateChunk(Key);

 

A direct consequence of this is to link a *.3dm to *.gh. Although a couple of components would be necessary to save and open the 3dm. However, it seems that File3dm class can not be serialized via System.Runtime.Serialization namespace. David, you know how to do this? And by the way, you allready know how it will be this point (link rhino and gh files) for GH2?

If (RhinoFile Is Nothing) Then
Throw New Exception("Path of RhinoFile is empty")
Return
End If
Dim Ghfile As String = grasshopperDocument.FilePath
If (GhFile Is Nothing) Then
Throw New Exception("Path of GhFile is empty. Save the current document first.")
Return
End If

Dim File3dm As Rhino.FileIO.File3dm = Rhino.FileIO.File3dm.Read(RhinoFile)

If (File3dm Is Nothing )Then
Throw New Exception("RhinoData is empty")
Return
End If

Dim formatter As System.Runtime.Serialization.IFormatter = New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim stream As New memoryStream()
formatter.serialize(Stream, File3dm)
Stream.Seek(0, 0)
Dim RhinoData As Byte() = Stream.ToArray()

Dim archive As New gh_archive()
If Not (archive.ReadFromFile(Ghfile)) Then
Throw New Exception("File could not be read")
End If

Dim root As gh_chunk = archive.GetRootNode()
If (root Is Nothing) Then
Throw New Exception("File has no root")
End If

Dim writer As Gh_Iwriter = root.CreateChunk("RhinoDocument")
writer.SetByteArray(Rhinodoc.ActiveDoc.Name, RhinoData)
archive.WriteToFile(GhFile, True, False)

stream.Close()

With that code I get this error:

error: El tipo 'Rhino.FileIO.File3dm' del ensamblado 'RhinoCommon, Version=5.1.30000.15, Culture=neutral, PublicKeyToken=552281e97c755530' no está marcado como serializable. (line: 0)

((The type file3dm ...blablabla... It is not marked as serializable.))

I tried also using Rhino.FileIO namespace, but something is bad, the error was:
Error: ReadCompressedBuffer failed (line: 0)

If (RhinoFile Is Nothing) Then
Throw New Exception("Path of RhinoFile is empty")
Return
End If
Dim Ghfile As String = grasshopperDocument.FilePath
If (GhFile Is Nothing) Then
Throw New Exception("Path of GhFile is empty. Save the current document first.")
Return
End If

Dim RhinoArchive As New rhino.FileIO.BinaryArchiveFile (RhinoFile, rhino.FileIO.BinaryArchiveMode.Read3dm)

If (RhinoArchive.Open) Then

Dim RhinoReader As rhino.FileIO.BinaryArchiveReader = RhinoArchive.Reader()
Dim RhinoData As Byte() = RHinoreader.ReadCompressedBuffer()

If (RhinoData Is Nothing )Then
Throw New Exception("RhinoData is empty")
Else

Dim archive As New gh_archive()
If Not (archive.ReadFromFile(Ghfile)) Then
Throw New Exception("File could not be read")
End If

Dim root As gh_chunk = archive.GetRootNode()
If (root Is Nothing) Then
Throw New Exception("File has no root")
End If

Dim writer As Gh_Iwriter = root.CreateChunk("RhinoDocument")
writer.SetByteArray(Rhinodoc.ActiveDoc.Name, RhinoData)
archive.WriteToFile(GhFile, True, False)

End If

Else
Throw New Exception("RhinoFile could not be read")
End If
Rhinoarchive.Close()
Rhinoarchive.Dispose()

Well, you'd only use the CommonObjectToByteArray method to convert something like a Mesh or a Brep or a Curve into the OpenNurbs byte data. You don't have to convert strings to byte-arrays, as you can store strings directly with writer.SetString(). Or you can store numbers directly with writer.SetDouble() etc. etc.


Thank you David this seems logical, but apparently I can not change the code accordingly , sorry to disturb you for that.

My code:

private void RunScript(string source, string target, string Key, List<string> Texts, ref object A)
{
GH_Archive archive = new GH_Archive();
if (!archive.ReadFromFile(source))
throw new Exception("File could not be read");

GH_Chunk root = archive.GetRootNode;
if (root == null)
throw new Exception("File has no root");

GH_IWriter writer = root.CreateChunk(Key);

int index = -1;
foreach (string txt in Texts)
{
index++;
writer.SetString("txt", index);
}

//System.IO.File.WriteAllBytes(target, archive.Serialize_Binary());
archive.WriteToFile(target, true, false);
}

Apparently there is a problem with:
{index++;
writer.SetString("txt", index);}

Best,

writer.SetString("txt", index);

should be 

writer.SetString("KeyName", index, txt);

RSS

About

Translate

Search

Photos

  • Add Photos
  • View All

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service