Revit API 实体搭接部分体积的获取

最近有个工程预算方面的项目,需要获取到两个实体搭接部分的体积,通过网络查找和SDK 文档与Demo的阅读,总结出以下解决方案,有需要的同学可以参考下,开发的SDK版本为2013。

namespace VolumnOfJoint
{
    [Transaction(TransactionMode.Manual)]
    class CsCompute : IExternalCommand
    {
        Application app = null;
        Document doc = null;
        
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            doc = commandData.Application.ActiveUIDocument.Document;

            app = commandData.Application.Application;


            Parameter paramVolume = null;

            Transaction transaction = new Transaction(doc);

            transaction.Start("Compute volume of joint");

            GetSharedParamters(ref paramVolume);

            //VolumeCalculationOptions options = doc.Settings.VolumeCalculationSetting.VolumeCalculationOptions;
            //options.VolumeComputationEnable = true;
            //doc.Settings.VolumeCalculationSetting.VolumeCalculationOptions = options;

            UIDocument curDoc = commandData.Application.ActiveUIDocument;

            IList<Reference> elemRefSet = null;

            try
            {
               elemRefSet = curDoc.Selection.PickObjects(ObjectType.Element, "Please select two elemets");
            }
            catch (Autodesk.Revit.Exceptions.OperationCanceledException)
            {
                transaction.RollBack();

                return Result.Succeeded;
            }
 
            int elemSelCount = elemRefSet.Count;

            if (elemSelCount != 2)
            {
                TaskDialog.Show("Warning", "Please select two elemets!");
            }
            else
            {
                Element elem1th = doc.GetElement(elemRefSet[0]);
                Element elem2th = doc.GetElement(elemRefSet[1]);

                Solid soid1th = GetSolid(elem1th);
                Solid soid2th = GetSolid(elem2th);

                string computeInfo = "";
                bool computeSuccess = false;
                double volumnJoint = 0.0f;

                if (soid1th != null && soid2th != null)
                {
                    Solid soidJoint = BooleanOperationsUtils.ExecuteBooleanOperation(soid1th, soid2th, BooleanOperationsType.Intersect);
                    if (soidJoint != null)
                    {
                        volumnJoint = soidJoint.Volume;
                        computeSuccess = true;
                    }
                }

                if (computeSuccess)
                {
                    computeInfo = "Element:" + elem1th.Name + "\r\n";
/*
                    computeInfo += "Surface Area:" + soid1th.SurfaceArea + "\r\n";
                    computeInfo += "Volume:" + soid1th.Volume + "\r\n";
*/ 
                    paramVolume.Set(soid1th.Volume);
                    computeInfo += "Volume:" + paramVolume.AsValueString() + "\r\n" + "\r\n";

                    computeInfo += "Element:" + elem2th.Name + "\r\n";
/*
                    computeInfo += "Surface Area:" + soid2th.SurfaceArea + "\r\n";
                    computeInfo += "Volume:" + soid2th.Volume + "\r\n";
*/ 
                    paramVolume.Set(soid2th.Volume);
                    computeInfo += "Volume:" + paramVolume.AsValueString() + "\r\n" + "\r\n";

//                  computeInfo += "Volume of Joint:" + volumnJoint + "\r\n";
                    paramVolume.Set(volumnJoint);
                    computeInfo += "Volume of Joint:" + paramVolume.AsValueString();

                    TaskDialog.Show("Compute Success", computeInfo);
                }
                else
                {
                    TaskDialog.Show("Compute failed", "Can not get the volume of joint!");
                }

            }

            transaction.RollBack();

            return Result.Succeeded;
        }

        public Solid GetSolid(Element elem)
        {
            Options opt = new Options();
            opt.ComputeReferences = true;
            opt.IncludeNonVisibleObjects = false;

            GeometryElement geoElem = elem.get_Geometry(opt);

            foreach (GeometryObject geomObj in geoElem)
            {
                if (geomObj is Solid)
                {
                    Solid solidTmp = geomObj as Solid;
                    if (solidTmp != null && solidTmp.Faces.Size > 0)
                    {
                        return solidTmp;
                    }
                }
                else if (geomObj is GeometryInstance)
                {
                    GeometryInstance geoInst = geomObj as GeometryInstance;

                    GeometryElement geoElemTmp = geoInst.GetInstanceGeometry();

                    foreach (GeometryObject geomObjTmp in geoElemTmp)
                    {   
                        Solid solidTmp = geomObjTmp as Solid;
                        if (solidTmp != null && solidTmp.Faces.Size > 0)
                        {
                            return solidTmp;
                        }
                      
                    }
                }
            }

            return null;
        }


        public void GetSharedParamters(ref Parameter paramVolumn)
        {
          
            AddSharedParamters();

            Element elemProjectInfo = GetProjectInfoElem();

            paramVolumn = elemProjectInfo.get_Parameter("myVolume");

        }
        public void AddSharedParamters()
        {
            string sharedParameterFile = "c:\\sharedParamter.txt";

            FileStream fileStream = File.Create(sharedParameterFile);
            fileStream.Close();

            app.SharedParametersFilename = sharedParameterFile;
            DefinitionFile fileDef = app.OpenSharedParameterFile();

            DefinitionGroups myGroups = fileDef.Groups;
            DefinitionGroup myGroup = myGroups.Create("MyParameters");

            Definition myDefinition_Volume = myGroup.Definitions.Create("myVolume", ParameterType.Volume, true);
            //            Definition myDefinition_SurfaceArea = myGroup.Definitions.Create("mySurfaceArea", ParameterType.SurfaceArea, true); ParameterType.SurfaceArea seems dosen't supported

            CategorySet myCategories = app.Create.NewCategorySet();

            Category myCategory = doc.Settings.Categories.get_Item(BuiltInCategory.OST_ProjectInformation);

            bool visible = myCategory.AllowsBoundParameters;

            myCategories.Insert(myCategory);

            //Create an object of InstanceBinding according to the Categories
            InstanceBinding instanceBinding = app.Create.NewInstanceBinding(myCategories);

            BindingMap bindingMap = doc.ParameterBindings;

            // Bind the definitions to the document
            bindingMap.Insert(myDefinition_Volume, instanceBinding);
//            bindingMap.Insert(myDefinition_SurfaceArea, instanceBinding);

        }

        public Element GetProjectInfoElem()
        {
            FilteredElementCollector collector = new FilteredElementCollector(doc);
            collector.OfCategory(BuiltInCategory.OST_ProjectInformation);
            IList<Element> elems = collector.ToElements();

            return elems[0];
        }  

    }
}


这里需要注意下,一定要先将需要检测的两个实体转换到世界坐标空间下再调用接口进行搭接部分体积计算,不然这两个实体仅仅是Symbol,不可能有交集的,返回的交接部分实体的体积自然为0,即对于GeometryInstance一定要调用GetInstanceGeometry()而不是GetSymbolGeometry(), 还有一点需要注意的是单位问题,Revit内部是以固定的单位做实际的数据存储和运算而并不是以用户在项目单位中所设置的单位,那么在实际存储数据与上层项目表现和操作数据之间就会出现单位转换的问题,经过测试发现这里的计算出的体积单位是立方英尺, 可以手动强制转换,我这里是使用共享参数的方式让Revit自行换算出最终符合当前项目单位设置的结果,这种方式应该最合适的。


可供参考资料:

http://en.wikipedia.org/wiki/Constructive_solid_geometry

SDK Samples\GeometryAPI\GeometryCreation_BooleanOperation


  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Revit API中,获取柱子的所有面需要经过以下步骤: 1. 首先,通过Revit API中的过滤器,使用ElementClassFilter或ElementCategoryFilter来获取所有柱子元素的列表。 2. 遍历柱子元素列表,使用IsElementCategorized为真来判断柱子是不是一个实例化的元素。如果柱子是实例化的元素,使用Instance.GetGeometryObjectFromReference方法将其转换成几何对象。 3. 将几何对象转换成Solid类型,通过Solid.Faces属性获取所有的面。使用Solid.Faces.Size方法获取面的数量。 4. 遍历面的集合,使用Face.ComputeNormal方法获取每个面的法线,使用Face.Evaluate方法获取面的顶点坐标。 5. 将每个面的顶点坐标和法线存储在集合中,并依次遍历输出。 以下是一个示例代码来获取柱子的所有面: ```csharp UIApplication uiapp = commandData.Application; UIDocument uidoc = uiapp.ActiveUIDocument; Document doc = uidoc.Document; // 定义过滤器获取所有柱子元素 FilteredElementCollector collector = new FilteredElementCollector(doc); collector.OfCategory(BuiltInCategory.OST_Columns); collector.OfClass(typeof(FamilyInstance)); List<Element> columnElements = collector.ToElements().ToList(); foreach (Element element in columnElements) { if (element is FamilyInstance instance) { // 将柱子元素转换为几何对象 Options options = new Options(); options.ComputeReferences = true; options.View = uidoc.ActiveView; GeometryElement geometryElement = instance.get_Geometry(options); foreach (GeometryObject geometryObject in geometryElement) { if (geometryObject is Solid solid) { // 获取所有面 foreach (Face face in solid.Faces) { // 获取面的法线和顶点坐标 XYZ normal = face.ComputeNormal(new UV()); IList<XYZ> vertices = face.Triangulate().Vertices; // 输出顶点坐标和法线 foreach (XYZ vertex in vertices) { // 输出顶点坐标 TaskDialog.Show("Revit", "顶点坐标:" + vertex.ToString()); } // 输出法线 TaskDialog.Show("Revit", "法线:" + normal.ToString()); } } } } } ``` 以上就是使用Revit API获取柱子的所有面的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值