Creating a list of element IDs and IFC GUIDs

Creating a list of element IDs and IFC GUIDs

Anonymous
Not applicable
4,676 Views
8 Replies
Message 1 of 9

Creating a list of element IDs and IFC GUIDs

Anonymous
Not applicable

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;
        }
    }
}

 

0 Likes
Accepted solutions (2)
4,677 Views
8 Replies
Replies (8)
Message 2 of 9

ollikat
Collaborator
Collaborator
Accepted solution

Hi

 

What is this "GetElementId()"?

 

You should get an element id directly from element like this:

 

Element foo;
int bar = foo->Id->IntegerValue;

 

Message 3 of 9

Anonymous
Not applicable

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?

0 Likes
Message 4 of 9

ollikat
Collaborator
Collaborator
Accepted solution

Aa...sorry, my bad. I accidentally mixed C++ syntax to the code. Just use '.' instead

Message 5 of 9

Anonymous
Not applicable

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?

0 Likes
Message 6 of 9

ollikat
Collaborator
Collaborator

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

Message 7 of 9

Anonymous
Not applicable

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 😄

0 Likes
Message 8 of 9

Anonymous
Not applicable

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);
        }
    }
}

 

 

 

0 Likes
Message 9 of 9

Anonymous
Not applicable

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)

0 Likes