Copy DirectShape geometry from DocB to DocA without changing the ElementId.

Copy DirectShape geometry from DocB to DocA without changing the ElementId.

aniket_pachore
Enthusiast Enthusiast
233 Views
10 Replies
Message 1 of 11

Copy DirectShape geometry from DocB to DocA without changing the ElementId.

aniket_pachore
Enthusiast
Enthusiast
Hi all,
I am trying to update the geometry of a DirectShape element in DocA with geometry coming from a IFC model (DocB).
I’m able to copy the geometry successfully, but the issue is:
The previous geometry of the DirectShape in DocA is not erased or overridden.
Instead, it seems to accumulate geometry.

Here is the function I’m using:

 

private static void UpdateDirectShapeGeometry(Document docA, Element hostElem, Element modifiedElement)
{
    if (hostElem is DirectShape hostDs && modifiedElement is DirectShape linkedDs)
    {
        // Extract geometry from modified element
        Options geomOptions = new Options
        {
            ComputeReferences = true,
            DetailLevel = ViewDetailLevel.Fine
        };
        GeometryElement geomElem = modifiedElement.get_Geometry(geomOptions);

        if (geomElem != null)
        {
            List<GeometryObject> newGeom = new List<GeometryObject>();
            foreach (GeometryObject obj in geomElem)
                newGeom.Add(obj);

            if (newGeom.Count > 0)
            {
                try
                {
                    // Clear old geometry and apply new one
                    hostDs.SetShape(newGeom);
                }
                catch (Exception ex)
                {
                    TaskDialog.Show("Error", $"Failed to update DirectShape geometry: {ex.Message}");
                }
            }
        }
    }
}


Is it possible to change or override the DirectShape geometry using API?

0 Likes
Accepted solutions (1)
234 Views
10 Replies
Replies (10)
Message 2 of 11

longt61
Advocate
Advocate

Since DirectShape does not have any method for getting or removing geometry, I don't think that is possible. From your title, I guess that you don't want to delete then re-create the DirectShape because you use its ID as input for schedule, parameter formulas or even other addin command. Maybe you can try to modify the logic for your addin command, or whatever it is, to:
1. Create a shared parameter/ project parameter, for example: "my_id", then assign it to GenericModel, or whatever category you assign to your DirectShape.

2. Generate a GUID for "my_id", then use it for further calculation.

3. Next time when you update the geometry, just delete the existing DirectShape, create a new one and restore the GUID in "my_id".

This is the easier way, but it will affect all elements of GenericModel category, or whatever category you use.

An other way that I can think of is that you create a DirectShape with Type, get the Family from Type then create a Family parameter for it. This way, the parameter only applies to the DirectShape that you created. Even though this is available to Revit user, but I am not sure if it is for Revit API due to the fact that DirectShape family can not be edited manually.
Hope this helps

0 Likes
Message 3 of 11

aniket_pachore
Enthusiast
Enthusiast

Thanks for your valuable reply @longt61 ,

To clarify my situation: I have two models (ModelA <> DocA and ModelB <> DocB) imported from an external application as IFC Revit models. My goal is to update the modified elements from ModelB into ModelA without losing the tags that reference elements in ModelA.

As you mentioned, deleting the existing DirectShape and recreating a new one would generate a new ElementId, which would cause those tags to lose their references — something I want to avoid.

In short, my question is: can I replace only the geometry of a DirectShape without deleting the element itself, so that the ElementId remains unchanged?
If that’s not possible, would it be feasible to store the tag information before deleting the old element and then reattach the tags to the new element, all while keeping the same IFC GUID?

Thanks again for your time and guidance.



0 Likes
Message 4 of 11

longt61
Advocate
Advocate

I am afraid that there is no way to achieve what you want, at least I can not find a way to do it. 

Since the geometry of direct shape can not be removed, it will only accumulate over time. There is a class call DirectShapeLibrary that stores and manages geometry for DirectShape in a project for reuse, but it can not interfere in each DirectShape instance 's geometry. Therefore, you can not retain the DirectShape from IFC file. Maybe you can find solution in design convention via shared parameter as I have suggested.


P/S: You can retain the tag by this work around:

1. Create a dummy element

2. Use IndependentTag.AddReferences method to add reference to the dummy element

3. Replace the old DirecShape with a new one, which make the tag loses reference to the old one.

4. Add reference to the new DirectShape

5. Delete the dummy element.

In some cases, you don't need to create a dummy element, but in other cases you need to do so to avoid the tag or annotation being deleted along with the element, if my recollection is correct. Anyways, because you can not retain the element ID or IFC GUID, which is automatically generate for each element when the IFC file is created, the work around is just "nice to have".

0 Likes
Message 5 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @aniket_pachore  and @longt61 ,

 

 

As far as I know, DirectShape.SetShape() provides exactly this functionality — it replaces the geometry of an existing element.

 

I’m not entirely sure what you mean by “it accumulates geometry.” In my testing, I created a cone and a sphere as DirectShape elements. When I replaced the cone DirectShape with the sphere using SetShape(), I only saw the spheres (i.e., the geometry was replaced, not accumulated).

 

When using standard geometry methods, SetShape() behaves as a “replace shape” operation. The same applies to DirectShapeType.

 

Could I be misunderstanding your scenario?

 

Additionally, for working with DirectShape tags, you may find the following methods useful as a starting point:

 


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes
Message 6 of 11

aniket_pachore
Enthusiast
Enthusiast

Hi @naveen.kumar.t ,

You are absolutely right. I was using the SetShape() method to replace the geometry of a DirectShape, expecting that it would overwrite the old geometry with the new one.

However, in my case the DirectShape elements are externally owned — they come from Tekla (exported as IFC, then saved in Revit as .rvt), and I am processing them further in Revit. When I try to replace the geometry, the new geometry ends up overlapping the old one instead of replacing it.

Could it be that Revit treats externally owned DirectShape elements as imported or “baked” geometry, meaning they are not fully editable through the API in the same way as elements created directly with DirectShape.CreateElement() ? I might be wrong, but could it be a possible reason?

Thanks for the reply and suggesting the DirectShape Tag methods.

Also your suggestion will be helpful @longt61 .






0 Likes
Message 7 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @aniket_pachore ,

 

Could you please provide a minimal reproducible case for me to pass on to the development team for further analysis?

  • A short exact description of what you are trying to achieve.
  • The behaviour you observe versus what you expect, and why this is a problem.
  • A complete yet minimal, non-confidential Revit sample model to run a test in.
  • A complete yet minimal, non-confidential Visual Studio solution with add-in manifest that can be compiled, loaded, run and debugged with a single click to analyse its behaviour live in the sample model.
  • Detailed step-by-step instructions for reproducing the issue, e.g. which element to pick, what command to launch etc.
  • Revit Version details

Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes
Message 8 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support
Accepted solution

Hi @aniket_pachore ,

 

The Engineering team mentioned that if you are using Revit 2024.2 or newer with the default IFC link, the setShape approach is not used. Instead, it relies on externally tagged geometry, so using a combination of resetExternallyTaggedGeometry and setShape would prevent the overlap.


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes
Message 9 of 11

aniket_pachore
Enthusiast
Enthusiast

Hi @naveen.kumar.t ,

Thanks for the approach.
Yes I'm using Revit 2025.
I will try the approach you mentioned.
If possible can you please send any link or refer any code where this approach is used. So that it will be easy to understand the "resetExternallyTaggedGeometry".

Thanks and Best Regards,
Aniket Pachore.

0 Likes
Message 10 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @aniket_pachore ,

 

I am not aware of any readily available sample code for this. The closest reference I could find is the "SDK\Samples\GeometryAPI\UpdateExternallyTaggedBRep" sample included in the Revit SDK.

 

This sample shows how UpdateExternallyTaggedBRep can be used for creation and updating the geometry using DirectShape/DirectShapeType

 

If you encounter any issues, please share them here along with minimal details and non-confidential files that can help reproduce the problem. I will do my best to assist you in resolving it.


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes
Message 11 of 11

aniket_pachore
Enthusiast
Enthusiast

Hi @naveen.kumar.t ,

Thanks for your assistance.

The combination of resetExternallyTaggedGeometry and setShape worked perfectly to replace the geometry and avoid the overlap issue.

Dropping the line of code here in case it helps anyone facing the same problem.


Also Thanks to @longt61 for helping clarify the approach.

Thanks and Best Regards,
Aniket Pachore.


private static void UpdateDirectShapeGeometry(Document docA, Element hostElem, Element linkedElem)
{
    if (hostElem is DirectShape hostDs && linkedElem is DirectShape linkedDs)
    {
        Options geomOptions = new Options
        {
            ComputeReferences = true,
            DetailLevel = ViewDetailLevel.Fine
        };

        GeometryElement geomElem = linkedElem.get_Geometry(geomOptions);
        if (geomElem == null)
            return;

        List<GeometryObject> newGeom = new List<GeometryObject>();

        // --- Extract usable geometry (Solids, Meshes) ---
        foreach (GeometryObject obj in geomElem)
        {
            if (obj is GeometryInstance gi)
            {
                foreach (GeometryObject instObj in gi.GetInstanceGeometry())
                {
                    if (instObj is Solid s && s.Volume > 1e-6)
                        newGeom.Add(s);
                    else if (instObj is Mesh m && m.NumTriangles > 0)
                        newGeom.Add(m);
                }
            }
            else if (obj is Solid s2 && s2.Volume > 1e-6)
            {
                newGeom.Add(s2);
            }
            else if (obj is Mesh m2 && m2.NumTriangles > 0)
            {
                newGeom.Add(m2);
            }
        }

        if (newGeom.Count == 0)
        {
            TaskDialog.Show("Update Geometry", "No valid solids/meshes found in linked element.");
            return;
        }

        try
        {
            using (SubTransaction st = new SubTransaction(docA))
            {
                st.Start();

                // --- Clear old geometry first ---
                try
                {
                    hostDs.ResetExternallyTaggedGeometry();
                }
                catch
                {
                    // Older Revit versions may not have this API 
                }

                // --- Replace with new geometry ---
                hostDs.SetShape(newGeom);

                st.Commit();
            }
        }
        catch (Exception ex)
        {
            TaskDialog.Show("Error", $"Failed to update DirectShape geometry: {ex.Message}");
        }
    }
}