简体   繁体   English

如何使用Revit API检索墙的原始几何图形?

[英]How to retrieve a wall 's original geometry using Revit API?

In a project I need to export a wall 's original geometry to IFC file. 在一个项目中,我需要将墙的原始几何图形导出到IFC文件。 The so-called original geometry is the geometry of a wall without being cut by doors or windows hosted on the wall, without connections with roofs, floors, beams, columns, etc. The original geometry I wanted usually should be a shape likes box. 所谓的原始几何形状是指壁的几何形状,而不会被墙壁上的门或窗户切割,也没有与屋顶,地板,横梁,圆柱等连接。我想要的原始几何形状通常应该是类似盒子的形状。

Unfortunately there is no direct Revit API that gives me a wall's original geometry. 不幸的是,没有直接的Revit API可以给我墙的原始几何形状。 The element.get_Geometry method return the finally geometry cut by doors, windows and connected floors, roofs, etc. element.get_Geometry方法返回由门,窗以及相连的地板,屋顶等切割的最终几何图形。

One possible way to get a wall's original geometry is to rebuild geometry based on the wall's parameters myself, but my lazy method is to let Revit to do the work. 获取墙的原始几何形状的一种可能方法是自己根据墙的参数重建几何形状,但是我的懒惰方法是让Revit完成工作。 My method has five steps as following: 我的方法有五个步骤,如下所示:

Step 1: Start a Revit transaction. 步骤1:启动Revit交易。

Step 2: Before calling element.get_Geometry, temporarily delete the doors and windows hosted in the wall, as well as the roofs and floors connected with the wall, from the Revit document. 步骤2:在调用element.get_Geometry之前,请从Revit文档中临时删除墙壁上的门窗以及与墙壁相连的屋顶和地板。

Step 3: Call document.Regenerate method to updates the elements in the document. 步骤3:调用document.Regenerate方法更新文档中的元素。 Of course the wall's geometry should also be updated. 当然,墙的几何形状也应更新。

Step 4: Call element.get_Geometry to get original geometry that I wanted. 步骤4:调用element.get_Geometry以获取我想要的原始几何。

Step 5: Rollback the transaction so that the Revit document remains unchanged. 步骤5:回滚事务,以使Revit文档保持不变。

The problem comes out in Step 2. Even if I had delete the doors and windows, there is still openings in the returned geometry. 问题将在步骤2中解决。即使我删除了门窗,返回的几何图形中仍然有开口。

My question is, how to delete all elements related with a wall? 我的问题是,如何删除与墙相关的所有元素?

My Revit version is 2013. The .rvt file I used is rac_basic_sample_project.rvt shipped with Revit. 我的Revit版本是2013。我使用的.rvt文件是Revit随附的rac_basic_sample_project.rvt。 The wall I want export is the wall with id of 117698 or 117654. 我要导出的墙是ID为117698或117654的墙。

My project is based on Revit IFC exporter srouce code. 我的项目基于Revit IFC出口商的代码。

The following is the code segment I used to get original geometry: 以下是我用来获取原始几何图形的代码段:

private GeometryElement GetOriginalWallGeometry2(Element element)
{
    Document doc = element.Document;
    GeometryElement geomElem = null;
    //Step 1
    using (Transaction t = new Transaction(doc))
    {
        //Step 2:

        //delete wall joins
        Autodesk.Revit.DB.Wall wall = element as Autodesk.Revit.DB.Wall;

        //assert element is a wall
        //the joined floors or roofs can be deleted as expected.
        if (null != wall)
        {
            while (Autodesk.Revit.DB.WallUtils.IsWallJoinAllowedAtEnd(wall, 0))
            {
                Autodesk.Revit.DB.WallUtils.DisallowWallJoinAtEnd(wall, 0);
            }
            while (Autodesk.Revit.DB.WallUtils.IsWallJoinAllowedAtEnd(wall, 1))
            {
                Autodesk.Revit.DB.WallUtils.DisallowWallJoinAtEnd(wall, 1);
            }
        }

        //The following code of deleting doors doesn't work as expected.
        {
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            ICollection<Element> elementsList = collector.OfCategory(BuiltInCategory.OST_Doors).ToElements(); //here should be OST_Doors or others?

            foreach (Element elem in elementsList)
            {
                try
                {
                    doc.Delete(elem);
                }
                catch (System.Exception ex)
                {
                }
            }
        }

        //The following code of deleting windows doesn't work as expected.
        {
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            ICollection<Element> elementsList = collector.OfCategory(BuiltInCategory.OST_Windows).ToElements();//here should be OST_Windows or others?

            foreach (Element elem in elementsList)
            {
                try
                {
                    doc.Delete(elem);
                }
                catch (System.Exception ex)
                {
                }
            }
        }


        //The following code also doesn't work as expected.
        Autodesk.Revit.DB.HostObject hostObj = element as Autodesk.Revit.DB.HostObject;
        if (hostObj != null)
        {
            IList<ElementId> idlist = hostObj.FindInserts(true, true, true, true);
            foreach (ElementId id in idlist)
            {
                try
                {
                    doc.Delete(id);
                }
                catch (System.Exception ex)
                {
                }
            }
        }

        //Floors can be deteled as expected.
        {
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            ICollection<Element> linkList = collector.OfCategory(BuiltInCategory.OST_Floors).ToElements();

            foreach (Element elelink in linkList)
            {
                try
                {
                    doc.Delete(elelink);
                }
                catch (System.Exception ex)
                {

                }
            }
        }

        //Roofs can be deteled as expected.
        {
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            ICollection<Element> linkList = collector.OfCategory(BuiltInCategory.OST_Roofs).ToElements();

            foreach (Element elelink in linkList)
            {
                try
                {
                    doc.Delete(elelink);
                }
                catch (System.Exception ex)
                {

                }
            }
        }

        //Step 3
        doc.Regenerate();

        //Step 4
        Options options;
        View ownerView = element.Document.GetElement(element.OwnerViewId) as View;
        if (ownerView == null)
        {
            options = GeometryUtil.GetIFCExportGeometryOptions();
        }
        else
        {
            options = new Options();
            options.View = ownerView;
        }
        geomElem = element.get_Geometry(options);

        //Step 5
        FailureHandlingOptions failureOptions = t.GetFailureHandlingOptions();
        failureOptions.SetClearAfterRollback(true);
        failureOptions.SetDelayedMiniWarnings(true);
        t.SetFailureHandlingOptions(failureOptions);
        try
        {
            t.RollBack();
        }
        catch (System.Exception ex)
        {
        }
    }

    return geomElem;
}

I use the following method to retrieve elements of a particular category. 我使用以下方法来检索特定类别的元素。

    /// <summary>
    /// Get all elements of the specified type that fall into the specified category
    /// <para>The specified type must derive from Element, or you can use Element but you get everything :)</para>
    /// </summary>
    /// <typeparam name="T">The type of element to get</typeparam>
    /// <param name="builtInCategory">The BuiltinCategory to discriminate the element set</param>
    /// <returns>The collection of elements that match the type and specified categry</returns>
    public IEnumerable<T> GetElements<T>(BuiltInCategory builtInCategory) where T : Element
    {
        FilteredElementCollector collector = new FilteredElementCollector(Document);
        // Seems you must be a subclass of element to use the OfClass method
        if (typeof(T) != typeof(Element))
            collector.OfClass(typeof(T));
        collector.OfCategory(builtInCategory);
        return collector.Cast<T>();
    }

If you are trying to get doors and windows then it would be used as such 如果您要获取门窗,则将其用作

var doors = GetElements<FamilyInstance>(BuiltInCategory.OST_DOORS);
var windows = GetElements<FamilyInstance>(BuiltInCategory.OST_WINDOWS);

That presumes that the openings you are looking for are doors or windows. 假定您要寻找的开口是门或窗户。

If you are looking for void extrusions, etc, within the wall or other types of openings then you will need to be more specific in your question. 如果您正在墙壁或其他类型的开口中寻找空隙挤压等,那么您将需要在问题中更加具体。

As a more complex version of the function shown above I use the following method when I wish to also apply a filter against the elements being retrieved. 作为上面显示的函数的更复杂的版本,当我希望对要检索的元素也应用过滤器时,可以使用以下方法。

        /// <summary>
    /// Get the collection of elements of the specified type that are within the provided category that also pass the filter.
    /// <para>The specified type must derive from Element, or you can use Element but you get everything :)</para>
    /// </summary>
    /// <typeparam name="T">The type of element to get</typeparam>
    /// <param name="builtInCategory">The BuiltinCategory to discriminate the element set</param>
    /// <param name="filter">The filter to check the element against</param>
    /// <returns>The collection of elements of the specified type and specified category that pass the filter</returns>
    public IEnumerable<T> GetElements<T>(BuiltInCategory builtInCategory, ElementFilter filter) where T : Element
    {
        FilteredElementCollector collector = new FilteredElementCollector(Document);
        // Seems you must be a subclass of element to use the OfClass method
        if (typeof(T) != typeof(Element))
            collector.OfClass(typeof(T));
        collector.OfCategory(builtInCategory);
        collector.WherePasses(filter);
        return collector.Cast<T>();
    }

The advantage of using the method approach defined above is that it will isolate your code from Revit API changes in the future rather than using the same code blocks repeatedly throughout your code base. 使用上面定义的方法的好处是,它将在将来将您的代码与Revit API更改隔离开来,而不是在整个代码库中重复使用相同的代码块。

If you want to retrieve Windows, Doors and any other opening on the wall, this is the right code: 如果要检索窗户,门和墙上的任何其他开口,这是正确的代码:

var ids = (yourCurrentWallElement as Wall).FindInserts(true, true, true, true);
foreach (ElementId id in ids)
{
    var el = doc.GetElement(id);

    Debug.WriteLine(" Id: " + el.Id);
    Debug.WriteLine(" Type: " + el.GetType().Name);
    Debug.WriteLine(" Category: " + el.Category.Name);
    Debug.WriteLine(" Type: " + el.GetType().Name);

    if (el is FamilyInstance)
    {
        var fi = el as FamilyInstance;
        if (fi != null)
            Debug.WriteLine(" Symbol Name: " + fi.Symbol.Name);
    }
}

More info on the FindInserts -> http://revitapisearch.com/html/58990230-38cb-3af7-fd25-96ed3215a43d.htm 有关FindInserts的更多信息-> http://revitapisearch.com/html/58990230-38cb-3af7-fd25-96ed3215a43d.htm

Other example -> http://spiderinnet.typepad.com/blog/2012/04/get-wall-inserts-using-the-revit-wallfindinserts-net-api.html 其他示例-> http://spiderinnet.typepad.com/blog/2012/04/get-wall-inserts-using-the-revit-wallfindinserts-net-api.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM