Hello!
I’m trying to create a set of Revit families (Mass category) from a set of Rhino files (each Rhino file is used as a block in another Rhino file, and we want to recreate the same structure in Revit, so we have one Revit family per Rhino block).
All objects in our Rhino files are closed polysurfaces, so we’ve used already the Rhino.Inside workflow of ComponentFamilyForm - NewComponentFamily - SaveComponentFamily to create all the families at once. The problem is that each Rhino file has many objects inside, and the Revit families and the Revit project file end up being so heavy that we can’t open it with Enscape, being that a major problem for the team. We have aprox. 43 different Revit families, each of them sometimes with over 200 elements inside, and in the project we have 402 instances in total of these families altogether.
Therefore we decided to transform our closed polysurfaces into meshes before we migrate them into Revit. We need them to keep the material they have in Rhino, so the only way we found to migrate them from Rhino into the Revit family is with AddGeometryDirectShape. The problem is that to use that component - correct me if I’m wrong please! - I need to have the Revit family open and as my active view. That means we need to do that process over 40 times every time we need to update the families. We tried using AddDirectShapeType, but I can’t give it a family name because I’m using Revit 2020 and it’s only available for Revit 2022 or above.
That’s why now I’m trying to automate the process with a C# component. So far I got to headless open the Revit family and select the material Id in it, create a TessellatedShape with the material assigned to each face, and place it as a DirectShape into the Revit family. The problem comes when I try to save and/or close the family, because it says I can’t use that method having another transaction, sub-transaction or group transaction open. The only transaction I create is the one to place the DirectShape in the file, and I check that it’s successfully committed, so I can’t figure out which other transaction I have open? I tried creating a separate transaction to open the Revit family and committing it, but it doesn’t work. I’ve also tried calling RhinoInside_AddGeometryDirectShape with NodeInCode but apparently it doesn’t find it.
I’ve attached the GH script and the Rhino and the Revit family files that I’m using to test it. See below the C# script too.
Thank you very much in advance!
RhinoBlockToRevitFamily_00.gh (15.6 KB)
TestFamily.3dm (160.0 KB)
TestFamily.rfa (492 KB)
using System;
using System.Collections;
using System.Collections.Generic;
using Rhino;
using Rhino.Geometry;
using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
using DB = Autodesk.Revit.DB;
using UI = Autodesk.Revit.UI;
using RIR = RhinoInside.Revit;
using RhinoInside.Revit.Convert.Geometry;
using Rhino.NodeInCode;
private void RunScript(DataTree<Point3d> meshPts, string Document, string MaterialName, ref object A)
{
//Lists
List<DB.XYZ> RvtPts = new List<DB.XYZ>();
List<DB.ElementId> materialsId = new List<DB.ElementId>();
//Call the category to be used
DB.BuiltInCategory BuiltCategory = DB.BuiltInCategory.OST_Roofs;
//Open the family document
DB.ModelPath filepath = new DB.FilePath(Document);
DB.Document familyDoc = RIR.Revit.ActiveDBApplication.OpenDocumentFile(Document); //document class
//Find material in familyDoc
SelectRevitMaterials(familyDoc, MaterialName, materialsId);
//Start a new TessellatedShapeBuilder
DB.TessellatedShapeBuilder builder = new DB.TessellatedShapeBuilder();
builder.OpenConnectedFaceSet(true);
//Add Faces to TessellatedShapeBuilder
//1.Transform Rhino 3DPoint into Revit XYZ
//2.Create TessellatedFace with XYZ vertices and add to builder
for (int i = 0; i < meshPts.BranchCount; i++)
{
for(int j = 0; j < meshPts.Branch(i).Count; j++)
{
Point3d pt = meshPts.Branch(i)[j];
RvtPts.Add(RIR.Convert.Geometry.GeometryEncoder.ToXYZ(pt));
}
DB.TessellatedFace newFace = new DB.TessellatedFace(RvtPts, materialsId[0]);
builder.AddFace(newFace);
RvtPts.Clear();
}
//Close set and build builder
builder.CloseConnectedFaceSet();
builder.Target = DB.TessellatedShapeBuilderTarget.AnyGeometry;
builder.Fallback = DB.TessellatedShapeBuilderFallback.Mesh;
builder.Build();
DB.TessellatedShapeBuilderResult result = builder.GetBuildResult();
//Open a transaction in the familyDoc to bake in it
bool autoTransaction = false;
using(var t = new DB.Transaction(familyDoc, "Create DirectShape"))
{
if(!familyDoc.IsModifiable)
{
t.Start();
autoTransaction = true;
try
{
DB.DirectShape ds = DB.DirectShape.CreateElement(familyDoc, new DB.ElementId(BuiltCategory));
ds.ApplicationId = "Application id";
ds.ApplicationDataId = "Geometry object id";
ds.SetShape(result.GetGeometricalObjects());
familyDoc.Regenerate();
}
catch(Exception ex)
{
throw new Exception("Error info:" + ex.Message);
}
finally
{
if(autoTransaction)
{
t.Commit();
}
}
}
}
//Save and close family doc
familyDoc.Close(true); //gives error !!!!
}
// <Custom additional code>
public static void SelectRevitMaterials(DB.Document doc, string materialName, List<DB.ElementId> materialsId)
{
DB.FilteredElementCollector collector = new DB.FilteredElementCollector(doc);
var materials = collector.WherePasses(new DB.ElementClassFilter(typeof(DB.Material)));
foreach(DB.Material mat in materials)
{
string docMatName = mat.Name;
if(docMatName == materialName)
{
DB.ElementId docMatId = mat.Id;
materialsId.Add(docMatId);
}
}
}