Import only selected linked blocks from a file?

Hello,

I have a file with ~3000 linked blocks in it (each is an individual instance, no dups). I was able to keep adding these and work on the file just fine and save, but now the file will not open - it takes a while but at the end when the file finishes opening, Rhino goes unresponsive for time long enough (hours), to assume it is not going to open.

Would there be any chance to read ‘some’ of the linked block instances form that file, so I could piece it back together reading just smaller chunks of the file and then separate it to make it less linked-block-heavy?
I don’t think there is a way in Rhino, but perhaps it would be possible via a script to pick which objects to read from a file?

thanks for any hints,

–jarek

Hi Jarek - there is a test command ImportFrom3dmFile that allows reading instances but you do not get to choose - it may be worth a try. I’ll poke around for a RhinoCommon way.

-Pascal

Hi Jarek,

Yes you can access objects in a file without opening the file in the “Rhino Application”.
Let me know if Pascals answer is not sufficient, and I try to dig up some code to get you started.

-Willem

Thank you both for the suggestions!
@Pascal - interesting command and would be handy in many other situations but it would not help with what I am trying to do - not only as you said is all or nothing, but also it seems to have a problem with linked blocks - even if I pick InstanceDefinition=Yes and then ModelGeometry=Yes with only InstanceReferences=Yes, the definitions import OK but there are no instances in the file, and BlockManager shows this by the name of each block definition:
image
It shows the instance count correctly, and also when trying to delete them prompts listing the instances, but the file is empty.
(Works fine with non-linked blocks)

@Willem . I would definitely be interested in any suggestions or code to try partial/selection object import. Ideal case scenario would be to get an alphabetically sorted list of objectIDs, so out of, say, 3000 I can pick 500, remember where I left of and continue in a separate file. I don’t know the inner mechanics but it would need to be smart enough to bring the linked block definitions for these instances I guess…

Thanks again for your help.

–jarek

Hi,
Don’t know if this will work but you could try opening the file as an attached file in a worksession. Open a blank file then attach it as a non active file. I wonder if it will open? Then you could make it active or maybe copy some of the blocks to the clipboard.
RM

Hi Roland, thanks, unfortunately when I hook up that file as a worksession the same freeze happens once the file is opened.

Hi Jarek,

Sorry, With my limited time available I was not able to come up with a solution.
Reading the info on the linked blocks is more obscure than I expected…

Maybe someone else will chime in
-Willem

Hello @Jarek

Here is some basic code to run in a Grasshopper component. I hope this script can extract the data from your file.

using System.Linq;

  private void RunScript(string filepath, object index)
  {
    var file = Rhino.FileIO.File3dm.Read(filepath);
    var definitions = (from def in file.AllInstanceDefinitions select def).ToArray();

    // If the definition is linked, then the GetObjectIds method returns an empty array.
    // > An object is a reference object if, and only if, it is on a reference layer.
    // > https://developer.rhino3d.com/api/RhinoCommon/html/P_Rhino_DocObjects_InstanceDefinition_IsReference.htm
    var ObjectIds = definitions[index].GetObjectIds();
    var objects = from id in ObjectIds select file.Objects.FindId(id);

    // For this demo, I inject the elements inside the current document.
    // Not in new InstanceDefinition
    var doc = RhinoDoc.ActiveDoc;

    var matindeices = new List <int> ();
    foreach (var obj in objects)
    {
      var attr = obj.Attributes;
      doc.Objects.Add(obj.Geometry, attr);
      switch (obj.Attributes.MaterialSource)
      {
        case Rhino.DocObjects.ObjectMaterialSource.MaterialFromLayer:
          // TODO
          break;
        case  Rhino.DocObjects.ObjectMaterialSource.MaterialFromParent:
          // TODO
          break;
        case Rhino.DocObjects.ObjectMaterialSource.MaterialFromObject:
          if (matindeices.Contains(attr.MaterialIndex)) break;
          var m = file.AllMaterials.FindIndex(attr.MaterialIndex);
          doc.Materials.Add(m);
          break;
      }
      // TODO: Probably other resources too (like textures)
    }
  }

jmv

Hello All,

thank you for your input and suggestions so far. The good news is the file finally opened, it took 2 days(!), next time I will know better before packing a file with 1000s of individual linked blocks as clearly Rhino performance is not there yet (they are not heavy, just many…), worked fine when the blocks were not linked but that made the file very heavy…At least now I can fix it.

@Willem - that’s what I was afraid of that coding this when it comes to linked blocks would be PITA.

@kitjmv - thanks for the code - I am not sure how to use it, I am not very familiar with GH and C# components. I still would like to try it for the future reference, so lmk please how I can put this into a working component, or a GH definition and try on the file.

cheers,

–jarek

Hello @Jarek

ImportBlock.gh (4.8 KB)

Hi @jmv,

Thank you very much, for sure that would be a good start… I tested with linked blocks file but it doesn’t seem to work; with non-linked blocks file, I can bring the block geometry as mesh, without textures or other properties (like material, layer etc.) I looked at the C# code and I see your comments there but I am clueless about how to go from there.
My ideal vision would be to be able to selectively import objects (blocks, regular geometry) from a file, and they would retain all their properties form the original file. I am sure this is a complex task with a lot of what-ifs, otherwise we would have it in Rhino by now!

Thanks again, I think I may have another use for your sample component.

Best,

–jarek

Yes, as William said, there is no ideal “Method” for this.
My code is an attempt to meet this need without having to load the document into Rhino, thanks to the FileIO API.

Anyway, there are many situations where it is useful to be able to import parts of one file into another.
Something like “Append” or “Link” in Blender.


(And in my case, importing a layer as a block will be nice.)

@pascal, Rhino 8 has planned an improvement of the block manager. Can you add this? it’s probably the right time.
jmv

1 Like

Hi Jarek,
I thought it was a long shot but worth a try. I see you were able to read the file after two days. I think you hold the record for a file that takes the longest time to open.
Glad it opened and you can continue working.
RM

Seems like selective block instance import is already possible for non-linked blocks via the command Pascal has shared. Maybe it could graduate to a regular command in V8…

What I would find super useful, and not sure if it is on the wish list somewhere already, is being able to selectively import individual objects from the file. It since Rhino does not enforce object names or unique names, it would need a more advanced UI, to filted by object types, by layers etc., ulitmately maybe using objectIDs as the final reference of what to bring…

Hi Roland, yeah, not proud of this record…There is definitely some bottleneck in Rhino when it comes to linked blocks as the same file with embeded blocks works fine.