Revit二次开发之细说链接文件的应用(布置建筑柱外皮,楼板开洞)

记得刚接触BIM技术的时候,那么所谓的六大专业,建筑,结构,水,暖,动,电利用Revit建模,就实行了各专业协同的建模方式,利用中心文件作为媒介,使各个专业能够链接其他专业的模型做进一步的工作,所以说到链接,最近整理了一下以前做过的项目——就是在建筑模型里链接结构模型,为结构柱放上建筑柱外皮,也就是我们常说的抹灰,一般是水泥砂浆做的,那么问题来了 如果这里有几百根结构柱需要放置外皮,那么人工来做的话则需要大量的时间,所以想到开发插件快速布置喽!

 

其实最大的问题是如何获得链接模型的Document 获得到它 我们就可以获得这个模型里每一个构件的参数信息

 

基本步骤如下:

1,首先使用LoadFamily方法将要放置的建筑柱外皮族载入到项目中(需要开启事务,当然这一步也可以排在最后):

2,其次写一个过滤器,为PickObject或PickObjects服务,这样可以直接选取链接模型的结构柱,过滤器如下:

 //拾取链接文档元素过滤器

    public class ColumnSelectionFilter : ISelectionFilter

    {

        public RevitLinkInstance instance = null;

        public bool AllowElement(Element elem)

        {

            instance = elem as RevitLinkInstance;

            if (instance != null)

            {

                return true;

            }

 

            return false;

        }

        public bool AllowReference(Reference reference, XYZ position)

        {

            if (instance == null)

            {

                return false;

            }

            else

            {

                Document linkdocument = instance.GetLinkDocument();

                FamilyInstance familyinstance = linkdocument.GetElement(reference.LinkedElementId) as FamilyInstance;

               //这里简单限制一下筛选条件

                if ((familyinstance.Symbol.Family.Name.Contains("混凝土") && familyinstance.Symbol.Family.Name.Contains("柱")))

                {

                    return true;

                }

                return false;

            }

        }

    }

3,通过pickobject方法 拾取到的构件引用转化为 RevitLinkInstance 进而得到链接模型的Document 

4,获得这个实例的参数,如,坐标,截面深度,宽度,标高和偏移量,当然如果细致点的话我门还需要判断它是否是矩形柱还是圆形柱,我们可以根据Face is CylindricalFace判断,本博文暂且不阐述,下边有介绍代码,那么这里要说的就是标高,我们知道结构模型的标高和建筑模型的标高肯定是有所不同的,所以会出现这种情况——结构柱所依赖的标高,建筑模型里没有,如果我们再把结构标高复制监视一遍,那样显得即复杂又琐碎。

      其实可以这样做一个转换——获得结构柱在原模型中的 底部高度和顶部高度值,然后在建筑模型里根据任意标高布置,只要设置它的底部和顶部高度值与原模型的一致即可,这样就可以省了很多事了!

5,那就是根据获得所有信息,传递给我们要放置的建筑外皮,实行参数一对一赋值,则大功告成!

代码步骤如下:

 public class Test : IExternalCommand

    {

        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)

        {

            UIApplication uiapp = commandData.Application;

            UIDocument uidoc = uiapp.ActiveUIDocument;

            Document doc = uidoc.Document;

            //首先将我们要用到的族载入到项目里 这里是用绝对路径

            LoadFamily(doc);

            Reference refer = uidoc.Selection.PickObject(ObjectType.LinkedElement, new ColumnSelectionFilter(), "请选择混凝土柱");

            //首先转化为RevitLinkInstance 就是为了获取连接文件的Document,当然还可以通过其他方式获取比如过滤项目的所有文档

            //如果IsLinked==true就是链接文档,这个只针对单链接文档 如果是多链接文档则要增加一些筛选条件了

            //Document linkDoc = null;

            //foreach (Document document in doc.Application.Documents)

            //{

            //    if (document.IsLinked && document.PathName.Contains("GT"))

            //    {

            //        linkDoc = document;

            //    }

            //}

            RevitLinkInstance linkInstance = doc.GetElement(refer) as RevitLinkInstance;

            Document linkDoc = linkInstance.GetLinkDocument();

            //获得标准的族实例

            FamilyInstance instance = linkDoc.GetElement(refer.LinkedElementId) as FamilyInstance;

            //目前获取到了 链接文件文档document也可以获得实例的各种参数

            //接下来就要获取链接柱的标高和偏移量了

            // 原始结构柱 顶标高 

            Parameter paramTop = instance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM);

            //顶部偏移量 

            Parameter paramTopoffset = instance.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM);

            //底标高    

            Parameter paramBase = instance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM);

            //底部偏移量

            Parameter paramBaseoffset = instance.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM);

 

            //设置两个变量用来接收 链接柱的长宽参数值

            double b = 0, h = 0;

            //获得链接柱的长宽参数

            GetOriginalRectangel(instance, ref b, ref  h);

 

            //获取链接柱的当前位置坐标XYZ

            XYZ xyz = (instance.Location as LocationPoint).Point;

 

            //到这里我们获得了链接柱的基本信息 包括截面长宽,标高和偏移量 接下来就是要设置我们要放置的建筑柱外皮族了

            //首先获得对应的类型

            FamilySymbol symbol = new FilteredElementCollector(doc).OfClass(typeof(FamilySymbol)).OfCategory(BuiltInCategory.OST_Columns).Where(o => o.Name == "建筑柱_矩形_水泥砂浆").First() as FamilySymbol;

            //获得标高,如果不用标高的话 生成的柱子的标高是只读的 这不符合我们的需求 这里获取最低的标高

            Level level = new FilteredElementCollector(doc).OfClass(typeof(Level)).OrderBy(o => (o as Level).ProjectElevation).First() as Level;

            

            //2016版要对未使用的族类型要进行激活

            //这里要开启事务 因为文档要发生改变了

            using (Transaction ts = new Transaction(doc, "add"))

            {

             

                ts.Start();

                if (symbol.IsActive == false)

                {

                    symbol.Activate();

                }

                //创建实例

                FamilyInstance NewInstance = doc.Create.NewFamilyInstance(xyz, symbol, level, StructuralType.NonStructural);

                //设置长宽 最后一个参数是建筑柱外皮的厚度这里给20mm

                SetRectangeWidth(NewInstance, h, b, 20 / 304.8);

                //设置标高偏移量,这里的document应该是链接文件的而不是当前项目的,因为我们要获得链接柱的信息 所以使用 linkDoc

                SetColumnParameter(linkDoc, NewInstance, paramTop, paramTopoffset, paramBase, paramBaseoffset,level);

                //设置材质 这里为了显而易见 就设置成黄色

                ColumnMaterial(doc, NewInstance, "涂料 - 黄色");

                ts.Commit();

 

            }

 

            return Result.Succeeded;

        }

        //载入建筑柱外皮族文件

        public void LoadFamily(Document doc)

        {

            try

            {

                Transaction ts = new Transaction(doc, "Load");

                ts.Start();

                doc.LoadFamily(@"C:\ProgramData\Autodesk\Revit\Addins\2016\BIM建筑工具\BIM\AEfamily\建筑柱_矩形_水泥砂浆.rfa");

                ts.Commit();

            }

            catch { }

        }

        //获得链接文件矩形柱的宽度,深度,我这里使用的参数为 b和h 

        //其实我们可以根据柱子的几何模型 获得它的顶面边的长度和宽度,但是有一点 如果这个矩形柱旋转过 还要进一步的判断

        //这里只提供一种常规的做法

        public void GetOriginalRectangel(FamilyInstance instance, ref double b, ref double h)

        {

            foreach (Parameter p in instance.Symbol.Parameters)

            {

                if (p.Definition.Name == "b")

                {

                    b = p.AsDouble();

                }

                if (p.Definition.Name == "h")

                {

                    h = p.AsDouble();

                }

            }

 

        }

        //设置建筑柱 矩形的长宽

        public void SetRectangeWidth(FamilyInstance familyInstance, double Deep, double Width, double deep)

        {

            foreach (Parameter p in familyInstance.Parameters)

            {

                if (p.Definition.Name == "内皮深度")

                {

                    p.Set(Deep);

                    foreach (Parameter p1 in familyInstance.Parameters)

                    {

                        if (p1.Definition.Name == "外皮深度")

                        {

                            p1.Set(deep + Deep);

                            break;

                        }

                    }

                    break;

                }

            }

            foreach (Parameter p in familyInstance.Parameters)

            {

                if (p.Definition.Name == "内皮宽度")

                {

                    p.Set(Width);

                    foreach (Parameter p1 in familyInstance.Parameters)

                    {

                        if (p1.Definition.Name == "外皮宽度")

                        {

                            p1.Set(deep + Width);

                            break;

                        }

                    }

                    break;

                }

            }

        }

        //设置建筑柱外皮材质

        public void ColumnMaterial(Document doc, FamilyInstance family, string materialName)

        {   

            Material mate = new FilteredElementCollector(doc).OfClass(typeof(Material)).Where(o => o.Name == materialName).First() as Material;

            foreach (Parameter p in family.Parameters)

            {

                if (p.Definition.Name == "柱外皮材质")

                {

                    p.Set(mate.Id);

                    break;

                }

            }

        }

        //设置建筑柱的标高和偏移量

        private void SetColumnParameter(Document linkDoc, FamilyInstance family, Parameter paramTop, Parameter paramTopffset, Parameter paramBase, Parameter paramBaseoffset,Level level)

        {

            Parameter OriginparamTop = family.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM);

            Parameter OriginparamTopoffset = family.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM);

            Parameter OriginparamBase = family.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM);

            Parameter OriginparamBaseoffset = family.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM);

            OriginparamTop.Set(level.Id);

            Level leTop = linkDoc.GetElement(paramTop.AsElementId()) as Level;

            OriginparamTopoffset.Set(leTop.ProjectElevation + paramTopffset.AsDouble());

            OriginparamBase.Set(level.Id);

            Level leBase = linkDoc.GetElement(paramBase.AsElementId()) as Level;

            OriginparamBaseoffset.Set(leBase.ProjectElevation + paramBaseoffset.AsDouble());

        }

        //判断 链接实例是矩形柱还是圆形柱 这里简单用截面去判断,这里只做简单的循环遍历

        public bool DetermineShape(FamilyInstance instance, UIApplication app)

        {

            Options option = app.Application.Create.NewGeometryOptions();

            GeometryElement groElement = instance.get_Geometry(option);

            foreach (GeometryObject geoObj in groElement)

            {

                if (geoObj is Solid && geoObj != null)

                {

                    Solid solid = geoObj as Solid;

                    if (solid.Faces.Size > 1)

                    {

                        foreach (Face face in solid.Faces)

                        {

                            PlanarFace pf = face as PlanarFace;

                              //判断截面形状

                            if (face is CylindricalFace)

                            {

                                return true;

                            }

                        }

                    }

                }

            }

 

            return false;

        }

 

    }

 

    //拾取链接文档元素过滤器

    public class ColumnSelectionFilter : ISelectionFilter

    {

        public RevitLinkInstance instance = null;

        public bool AllowElement(Element elem)

        {

            instance = elem as RevitLinkInstance;

            if (instance != null)

            {

                return true;

            }

 

            return false;

        }

        public bool AllowReference(Reference reference, XYZ position)

        {

            if (instance == null)

            {

                return false;

            }

            else

            {

                Document linkdocument = instance.GetLinkDocument();

                FamilyInstance familyinstance = linkdocument.GetElement(reference.LinkedElementId) as FamilyInstance;

                if ((familyinstance.Symbol.Family.Name.Contains("混凝土") && familyinstance.Symbol.Family.Name.Contains("柱")))

                {

                    return true;

                }

                return false;

            }

        }

    }

Revit二次开发之细说链接文件的应用(布置建筑柱外皮,楼板开洞)

Revit二次开发之细说链接文件的应用(布置建筑柱外皮,楼板开洞)

如果使用PickObjects或直接整项目过滤结构柱,则可以实现批量布置,如下图
Revit二次开发之细说链接文件的应用(布置建筑柱外皮,楼板开洞)
 

  

那么根据链接模型对结构楼板开洞 其实道理也是一样的,不管是给排水,暖通,动力,电气都好,使用的方法都是一样的,这里就不写的太详细了 说说步骤吧!

1,一样的我们要获得链接模型的Document,获得链接里的水管也好,风管也罢,获得他们的信息,长宽或者公称直径就是获得参数呗

2,那水管为例,如果这里只做垂直穿过楼板的,这需要获得水管的中心线和楼板上表面的交点可以使用

      Face.Intersect(Curve, out IntersectionResultArray)方法,当然在此之前你要获得楼板的上表面或下表面和       链接水管的Curve那么这些不是很难 如下:

 

      //获得管道的曲线与 楼板面做碰撞相交,其实可以更简单的获取

        public Curve FindPipeCurve(Pipe pipe)

        {

            IList list = new List();

            ConnectorSetIterator csi = pipe.ConnectorManager.Connectors.ForwardIterator();

            while (csi.MoveNext())

            {

                Connector conn = csi.Current as Connector;

                list.Add(conn.Origin);

            }

            Curve curve = Line.CreateBound(list.ElementAt(0), list.ElementAt(1)) as Curve;

            return curve;

        }

       //获得结构楼板的上表面

        public Face FindFloorFace(Floor floor)

        {

            Face normalFace = null;

            //Options option = new Options();

            //option.ComputeReferences = true;

            //GeometryElement element = floor.get_Geometry(option);

            //foreach (GeometryObject obj in element)

            //{

            //    Solid solid = obj as Solid;

            //    if (solid != null && solid.Faces.Size > 0)

            //    {

            //        foreach (Face face in solid.Faces)

            //        {

            //            PlanarFace pf = face as PlanarFace;

            //            if (pf != null)

            //            {

            //                if (pf.ComputeNormal(new UV(pf.Origin.X, pf.Origin.Y)).Normalize().Z == 1)

            //                {

            //                    normalFace = face;

            //                    break;

            //                }

            //            }

            //        }

            //    }

            //}

            normalFace = floor.GetGeometryObjectFromReference( HostObjectUtils.GetTopFaces(floor)[0]) as Face;

            return normalFace;

        }

3,获得线和面的交点 也就是开洞的圆心,代码如下:

 //获得相交点

        public XYZ FindXYZ(Face face, Curve curve)

        {

            IntersectionResultArray intersectionR = new IntersectionResultArray();

            SetComparisonResult comparisonR;

            comparisonR = face.Intersect(curve, out intersectionR);

            XYZ intersectionResult = null;

            if (SetComparisonResult.Disjoint != comparisonR)

            {

                if (!intersectionR.IsEmpty)

                {

                    intersectionResult = intersectionR.get_Item(0).XYZPoint;

                }

            }

            return intersectionResult;

        }

4,那就是根据水管的公称直径对楼板进行开洞了,当然给楼板开洞时要考虑给套管留有足够的空间。比如公称直径为100mm那么就要考虑开125mm的洞了 当然要按照标准来的 这里只是说说而已

     使用Document.Create.NewOpening(floor, curves, true)方法进行开洞操作,这里就不给大家贴图了,自行测试吧!

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值