Adding InstanceReferences to a File3dm object

Hello,

I want to add InstanceReferences to a newly created File3dm object, How can I do that?

Amongst the things I tried is adding the InstanceReferenceGeometry to the new file using

  file.Objects.AddinstanceObject(iRefGeo);

but that just created empty files, even though the InstanceReferenceGeometry itself was valid and the ObjectTable for that file is populated. Do I need to add the InstanceDefinitions? And how?
Or is there a better way?

    public void ExportBlocks(RhinoDoc doc, List<InstanceReferenceGeometry> instanceReferenceGeometries)
    {
        string path = "C:\\dummypath\\dummyfile.3dm";

        Rhino.FileIO.File3dm file = new Rhino.FileIO.File3dm();

        foreach (InstanceReferenceGeometry iRefGeo in instanceReferenceGeometries)
        {
            file.Objects.AddInstanceObject(iRefGeo);
        }

        file.Write(path, 6);
    }

Hi @rgr,

Try this (in Rhino 6):

protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
  var path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
  var filename = Path.Combine(path, "Test.3dm");

  Result rc;
  using (var file = new File3dm())
  {
    var layer = new Layer { Name = "Default", Color = Color.Black };
    file.AllLayers.Add(layer);

    var layer_index = file.AllLayers.Count - 1;
    var attribute = new ObjectAttributes { LayerIndex = layer_index };

    var geometry = new List<GeometryBase>();
    var attributes = new List<ObjectAttributes>();
    for (var x = 0; x < 10; x++)
    {
      var line_curve = new LineCurve(new Point3d(x, 0, 0), new Point3d(x, 1, 0));
      geometry.Add(line_curve);
      attributes.Add(attribute.Duplicate());
    }

    var idef_index = file.AllInstanceDefinitions.Add("Test", "Test Definition", Point3d.Origin, geometry, attributes);
    file.Objects.AddInstanceObject(idef_index, Transform.Identity, attribute);

    rc = file.Write(filename, 6) ? Result.Success : Result.Failure;
  }

  return rc;
}

– Dale

Hello @dale, thank you for the example.

I used the “Add Nested Block” example, which is baiscly the same, however I get a “*ERROR no geometry found for block definition” error in the new file.

My code basicly:

part.AddToDocument(doc);
var instanceDefId = doc.InstanceDefinitions[part.InstanceDefinitionIndex].Id;

var iRefGeo = new InstanceReferenceGeometry(instanceDefId, Transform.Identity);
GeometryBase[] blockList = { iRefGeo };

int indexOfAddedBlock = assemblyFile.AllInstanceDefinitions.Add(part.Name, "", Point3d.Origin, blockList);
assemblyFile.Objects.AddInstanceObject(indexOfAddedBlock, Transform.Identity);

where “part” is my own class which provides methods for inserting an external file as a embeddedandlinked block, also stores Id a name for that part.

What I am trying to achive is basicly this:

  • Insert file as embeddedandlinked block
  • Place block inside document
  • export couple of placed blocks to a new file
  • Insert the new file as a linked block, replacing the blocks placed in the second step

In the original document, I get the geometry as linked blocks just as I want, however, exporting seems to be a different kind of magic.

Hi @rgr,

To my knowledge, there isn’t a way of adding a linked instance definition to a 3dm file, via File3dm, using RhinoCommon.

– Dale

Hi @dale,

that is unfortunate as it is an important part of our process. Do you think that is a functionality that could be added in the future?

I’m going to make a workaround using “-Export”, but if I’m allowed to pick your brain, leaving all good practices behind: I experimented with adding the blocks to a new document, using the code below:

    public void CreateAssembly(RhinoDoc doc)
    {
        string assemblyPath = "C:\\filepath\\";

        RhinoDoc activeDoc = doc;

        RhinoDoc assemblyDoc = RhinoDoc.Create(null);
        assemblyDoc.AdjustModelUnitSystem(UnitSystem.Millimeters, false);
        assemblyDoc.ModelAbsoluteTolerance = 0.001;

        foreach (PartInstance part in Parts)
        {
            part.AddToDocument(assemblyDoc);
        }

        Rhino.FileIO.FileWriteOptions options = new Rhino.FileIO.FileWriteOptions();

        assemblyPath += this.Name + ".3dm";
        assemblyDoc.Write3dmFile(assemblyPath, options);

        //return to old document by adding and deleting a point
        Guid deleteID = activeDoc.Objects.AddPoint(Point3d.Origin);
        activeDoc.Objects.Delete(deleteID, true);
    }

What I experience here is that in the foreach-loop, the method “AddToDocument”, which is an internal one to insert .3dm files as blocks using RhinoDoc.Readfile, Rhino changes the active document, but when I try to return to the initial active doc by adding geometry to it, it won’t, and therefore my command does not continue properly. Is there any (undocumented) way to activly change the active document?
If I would be able to return to my old document I had everything, because the written file is exactly what I want.

No, sorry. The best you can do is script the New or Open commands.

https://mcneel.myjetbrains.com/youtrack/issue/RH-49968

– Dale

Thank you for adding that issue to the wishlist Dale!