加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

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

(2016-10-08 19:40:06)
标签:

365

it

分类: 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;
            }
        }
    }
http://s12/mw690/006AhjOXzy75sMFS5gT8b&690

http://s13/mw690/006AhjOXzy75sMFYaq8ac&690

如果使用PickObjects或直接整项目过滤结构柱,则可以实现批量布置,如下图
http://s10/mw690/006AhjOXzy75sMG18Bb39&690

  
那么根据链接模型对结构楼板开洞 其实道理也是一样的,不管是给排水,暖通,动力,电气都好,使用的方法都是一样的,这里就不写的太详细了 说说步骤吧!
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)方法进行开洞操作,这里就不给大家贴图了,自行测试吧!


   


0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有