I need a list of element IDs matched to their IFC GUIDs, but I'm not having much luck. I've tried piecing together a bit of what I know and what I've found, but I keep getting errors connected to the IDs : I can't get the element ID from an element, and I can't create the GUID to feed into an ifc converter. I imagine I'm making a total rookie mistake, as this is my first attempt to code in C#, but here you have it. Suggestions?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Diagnostics; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Architecture; using Autodesk.Revit.UI; using Autodesk.Revit.UI.Selection; using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.Attributes; using Autodesk.Revit.DB.IFC.ExporterIFCUtils; [TransactionAttribute(TransactionMode.Manual)] [RegenerationAttribute(RegenerationOption.Manual)] public class copyEverything : IExternalCommand { //Set the path for the new text file string myPath = @"c:\temp\MyTest.txt"; public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { //Get application and document objects UIApplication uiApp = commandData.Application; Document doc = uiApp.ActiveUIDocument.Document; var collector = new FilteredElementCollector(doc).WhereElementIsNotElementType() ; //Create a new text file and fill it with lines of elementIDs and IFC GUIDs, with a space in between using (StreamWriter myText = File.CreateText(myPath)) { foreach (Element x in collector) { //THIS IS WHERE I'M HAVING PROBLEMS var elemId = GetElementId(x); var tempNum = CreateGUID(x); //Convert the GUID to IFC format, and add a new line to the text file var tempIfcId = IfcGuid.cv_to_64( tempNum ); myText.WriteLine(elemId + " " + tempIfcId); } } return Result.Succeeded; } //Found function to convert GUID's into IFC's 64-bit scheme public static class IfcGuid { private static readonly char[] base64Chars = new char[] { '0','1','2','3','4','5','6','7','8','9' , 'A','B','C','D','E','F','G','H','I','J' , 'K','L','M','N','O','P','Q','R','S','T' , 'U','V','W','X','Y','Z','a','b','c','d' , 'e','f','g','h','i','j','k','l','m','n' , 'o','p','q','r','s','t','u','v','w','x' , 'y','z','_','$' }; public static void cv_to_64(uint number, ref char[] result, int start, int len) { uint act; int iDigit, nDigits; Debug.Assert(len <= 4); act = number; nDigits = len; for (iDigit = 0; iDigit < nDigits; iDigit++) { result[start + len - iDigit - 1] = base64Chars[(int)(act % 64)]; act /= 64; } Debug.Assert(act == 0, "Logic failed, act was not null: " + act.ToString()); return; } } }
Solved! Go to Solution.
Solved by ollikat. Go to Solution.
Solved by ollikat. Go to Solution.
Hi
What is this "GetElementId()"?
You should get an element id directly from element like this:
Element foo; int bar = foo->Id->IntegerValue;
Mostly a stab in the dark from searching through functions 🙂 Really new to this API and C# in general, so I really appreciate the help.
When I use that snippet of code, setting foo = to the element I'm looking at, I get an error saying "The * or -> operator must be applied to a pointer." I only have a vague idea of what a pointer is (researching more now), but is there something else I should be doing with this?
Awesome, that did it. Using that as a base, I think I have the right way to get the Unique ID for the cv_to_64 function too, so thanks!
Now I'm seeing that I'm not using that function right, though. Do you have any experience with it? I got it from here: http://thebuildingcoder.typepad.com/blog/2010/06/ifc-guid-algorithm-in-c.html
If I'm reading it right, it takes four arguments...trouble is, I don't really know what those four are supposed to be. I'd assume it only would have been the UniqueID, but that seems not to be the case. Any ideas?
I think you should be using ToIfcGuid() function instead. Here's one way to use it:
Guid elemGuid = Autodesk.Revit.DB.ExportUtils.GetExportId(element.Document, element.Id); String ifcGuid = IfcGuid.toIfcGuid(elemGuid);
Hope that is something you are looking for
That did it, I now have a text file that contains exactly what I was looking for!
Thanks a ton for your repeated help, I really appreciate it. This would have taken a lot longer without it 😄
And just in case anyone comes across this post looking to do the same thing, here's the working code. Note that it doesn't give any confirmation, it just exports the file.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Diagnostics; using Autodesk.Revit.DB; using Autodesk.Revit.DB.Architecture; using Autodesk.Revit.UI; using Autodesk.Revit.UI.Selection; using Autodesk.Revit.ApplicationServices; using Autodesk.Revit.Attributes; [TransactionAttribute(TransactionMode.Manual)] [RegenerationAttribute(RegenerationOption.Manual)] public class Lab1PlaceGroup : IExternalCommand { //Set the path for the new text file string myPath = @"c:\MyTest.txt"; public Result Execute( ExternalCommandData commandData, ref string message, ElementSet elements) { //Get application and document objects UIApplication uiApp = commandData.Application; Document doc = uiApp.ActiveUIDocument.Document; var collector = new FilteredElementCollector(doc).WhereElementIsNotElementType() ; //If there's an existing file at the path, delete it. if (File.Exists(myPath)) { File.Delete(myPath); } //Create a new text file and fill it with lines of elementIDs and IFC GUIDs, with a space in between using (StreamWriter myText = File.CreateText(myPath)) { //Cycle through all elements in the scene, identify their element ID and GUID, then convert GUID into IFC GUID. //Add both numbers to the text file with a space inbetween foreach (Element x in collector) { int elemId = x.Id.IntegerValue; Guid elemGuid = Autodesk.Revit.DB.ExportUtils.GetExportId(x.Document, x.Id); String tempNum = IfcGuid.ToIfcGuid(elemGuid); myText.WriteLine(elemId + " " + tempNum); } } return Result.Succeeded; } //Found function to convert GUID's into IFC's 64-bit scheme, available at http://thebuildingcoder.typepad.com/blog/2010/06/ifc-guid-algorithm-in-c.html public static class IfcGuid { /// <summary> /// The replacement table /// </summary> private static readonly char[] base64Chars = new char[] { '0','1','2','3','4','5','6','7','8','9' , 'A','B','C','D','E','F','G','H','I','J' , 'K','L','M','N','O','P','Q','R','S','T' , 'U','V','W','X','Y','Z','a','b','c','d' , 'e','f','g','h','i','j','k','l','m','n' , 'o','p','q','r','s','t','u','v','w','x' , 'y','z','_','$' }; /// <summary> /// Conversion of an integer into characters /// with base 64 using the table base64Chars /// </summary> /// <param name="number">The number to convert</param> /// <param name="result">The result char array to write to</param> /// <param name="start">The position in the char array to start writing</param> /// <param name="len">The length to write</param> /// <returns></returns> static void cv_to_64(uint number, ref char[] result, int start, int len) { uint act; int iDigit, nDigits; Debug.Assert(len <= 4); act = number; nDigits = len; for (iDigit = 0; iDigit < nDigits; iDigit++) { result[start + len - iDigit - 1] = base64Chars[(int)(act % 64)]; act /= 64; } Debug.Assert(act == 0, "Logic failed, act was not null: " + act.ToString()); return; } public static string ToIfcGuid(Guid guid) { uint[] num = new uint[6]; char[] str = new char[22]; int i, n; byte[] b = guid.ToByteArray(); // Creation of six 32 Bit integers from the components of the GUID structure num[0] = (uint)(BitConverter.ToUInt32(b, 0) / 16777216); num[1] = (uint)(BitConverter.ToUInt32(b, 0) % 16777216); num[2] = (uint)(BitConverter.ToUInt16(b, 4) * 256 + BitConverter.ToInt16(b, 6) / 256); num[3] = (uint)((BitConverter.ToUInt16(b, 6) % 256) * 65536 + b[8] * 256 + b[9]); num[4] = (uint)(b[10] * 65536 + b[11] * 256 + b[12]); num[5] = (uint)(b[13] * 65536 + b[14] * 256 + b[15]); // Conversion of the numbers into a system using a base of 64 n = 2; int pos = 0; for (i = 0; i < 6; i++) { cv_to_64(num[i], ref str, pos, n); pos += n; n = 4; } return new String(str); } } }
I've a 'reverse' question:
How can I retrieve an Elemento.UniqueId from an Ifc Guid?
(I've observed that Autodesk use an XOR exclusive to obtain the Ifc Guid from the first part of Element.UniqueId and the Element.Id)